def testWriteWithBinaryField(self):
        """
        Test writing with a binary field
        :return:
        """
        basetestpath = tempfile.mkdtemp()

        tmpfile = os.path.join(basetestpath, 'binaryfield.sqlite')
        ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
        lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid'])
        lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString))
        lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger))
        lyr.CreateField(ogr.FieldDefn('binfield', ogr.OFTBinary))
        lyr.CreateField(ogr.FieldDefn('binfield2', ogr.OFTBinary))
        f = None
        ds = None

        vl = QgsVectorLayer(tmpfile)
        self.assertTrue(vl.isValid())

        # check that 1 of its fields is a bool
        fields = vl.fields()
        self.assertEqual(fields.at(fields.indexFromName('binfield')).type(), QVariant.ByteArray)

        dp = vl.dataProvider()
        f = QgsFeature(fields)
        bin_1 = b'xxx'
        bin_2 = b'yyy'
        bin_val1 = QByteArray(bin_1)
        bin_val2 = QByteArray(bin_2)
        f.setAttributes([1, 'str', 100, bin_val1, bin_val2])
        self.assertTrue(dp.addFeature(f))

        # write a gpkg package with a binary field
        filename = os.path.join(str(QDir.tempPath()), 'with_bin_field')
        rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(vl,
                                                             filename,
                                                             'utf-8',
                                                             vl.crs(),
                                                             'GPKG')

        self.assertEqual(rc, QgsVectorFileWriter.NoError)

        # open the resulting geopackage
        vl = QgsVectorLayer(filename + '.gpkg', '', 'ogr')
        self.assertTrue(vl.isValid())
        fields = vl.fields()

        # test type of converted field
        idx = fields.indexFromName('binfield')
        self.assertEqual(fields.at(idx).type(), QVariant.ByteArray)
        idx2 = fields.indexFromName('binfield2')
        self.assertEqual(fields.at(idx2).type(), QVariant.ByteArray)

        # test values
        self.assertEqual(vl.getFeature(1).attributes()[idx], bin_val1)
        self.assertEqual(vl.getFeature(1).attributes()[idx2], bin_val2)

        del vl
        os.unlink(filename + '.gpkg')
Exemple #2
0
        def _round_trip(value, field, version='1.1.0'):
            """Set a value on fid 22 and field and check it back"""

            encoded_data = post_data.format(field=field, value=value, version=version).encode('utf8')
            # Strip the field if NULL
            if value is None:
                encoded_data = encoded_data.replace(b'<wfs:Value>None</wfs:Value>', b'')

            header, body = self._execute_request("?MAP=%s&SERVICE=WFS&VERSION=%s" % (
                self.testdata_path + 'test_project_wms_grouped_layers.qgs', version), QgsServerRequest.PostMethod, encoded_data)
            if version == '1.0.0':
                self.assertTrue(b'<SUCCESS/>' in body, body)
            else:
                self.assertTrue(b'<TotalUpdated>1</TotalUpdated>' in body, body)
            header, body = self._execute_request("?MAP=%s&SERVICE=WFS&REQUEST=GetFeature&TYPENAME=cdb_lines&FEATUREID=cdb_lines.22" % (
                self.testdata_path + 'test_project_wms_grouped_layers.qgs'))
            if value is not None:
                xml_value = '<qgs:{0}>{1}</qgs:{0}>'.format(field, value).encode('utf8')
                self.assertTrue(xml_value in body, "%s not found in body" % xml_value)
            else:
                xml_value = '<qgs:{0}>'.format(field).encode('utf8')
                self.assertFalse(xml_value in body)
            # Check the backend
            vl = QgsVectorLayer(
                self.testdata_path + 'test_project_wms_grouped_layers.gpkg|layername=cdb_lines', 'vl', 'ogr')
            self.assertTrue(vl.isValid())
            self.assertEqual(
                str(vl.getFeature(22)[field]), value if value is not None else 'NULL')
    def testStringArray(self):
        vl = QgsVectorLayer('%s table="qgis_test"."string_array" sql=' % (self.dbconn), "teststringarray", "postgres")
        self.assertTrue(vl.isValid())

        fields = vl.dataProvider().fields()
        self.assertEqual(fields.at(fields.indexFromName('value')).type(), QVariant.StringList)
        self.assertEqual(fields.at(fields.indexFromName('value')).subType(), QVariant.String)

        f = next(vl.getFeatures(QgsFeatureRequest()))

        value_idx = vl.fields().lookupField('value')
        self.assertIsInstance(f.attributes()[value_idx], list)
        self.assertEqual(f.attributes()[value_idx], ['a', 'b', 'c'])

        new_f = QgsFeature(vl.fields())
        new_f['pk'] = NULL
        new_f['value'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash']
        r, fs = vl.dataProvider().addFeatures([new_f])
        self.assertTrue(r)
        new_pk = fs[0]['pk']
        self.assertNotEqual(new_pk, NULL, fs[0].attributes())

        try:
            read_back = vl.getFeature(new_pk)
            self.assertEqual(read_back['pk'], new_pk)
            self.assertEqual(read_back['value'], new_f['value'])
        finally:
            self.assertTrue(vl.startEditing())
            self.assertTrue(vl.deleteFeatures([new_pk]))
            self.assertTrue(vl.commitChanges())
    def testHstore(self):
        vl = QgsVectorLayer('%s table="qgis_test"."dict" sql=' % (self.dbconn), "testhstore", "postgres")
        self.assertTrue(vl.isValid())

        fields = vl.dataProvider().fields()
        self.assertEqual(fields.at(fields.indexFromName("value")).type(), QVariant.Map)

        f = next(vl.getFeatures(QgsFeatureRequest()))

        value_idx = vl.fields().lookupField("value")
        self.assertIsInstance(f.attributes()[value_idx], dict)
        self.assertEqual(f.attributes()[value_idx], {"a": "b", "1": "2"})

        new_f = QgsFeature(vl.fields())
        new_f["pk"] = NULL
        new_f["value"] = {"simple": "1", "doubleQuote": '"y"', "quote": "'q'", "backslash": "\\"}
        r, fs = vl.dataProvider().addFeatures([new_f])
        self.assertTrue(r)
        new_pk = fs[0]["pk"]
        self.assertNotEqual(new_pk, NULL, fs[0].attributes())

        try:
            read_back = vl.getFeature(new_pk)
            self.assertEqual(read_back["pk"], new_pk)
            self.assertEqual(read_back["value"], new_f["value"])
        finally:
            self.assertTrue(vl.startEditing())
            self.assertTrue(vl.deleteFeatures([new_pk]))
            self.assertTrue(vl.commitChanges())
Exemple #5
0
    def testStringListField(self):
        source = os.path.join(TEST_DATA_DIR, 'stringlist.gml')
        vl = QgsVectorLayer(source)
        self.assertTrue(vl.isValid())

        fields = vl.fields()
        descriptive_group_field = fields[fields.lookupField('descriptiveGroup')]
        self.assertEqual(descriptive_group_field.type(), QVariant.List)
        self.assertEqual(descriptive_group_field.typeName(), 'StringList')
        self.assertEqual(descriptive_group_field.subType(), QVariant.String)

        feature = vl.getFeature(1000002717654)
        self.assertEqual(feature['descriptiveGroup'], ['Building'])
        self.assertEqual(feature['reasonForChange'], ['Reclassified', 'Attributes'])

        tmpfile = os.path.join(self.basetestpath, 'newstringlistfield.gml')
        ds = ogr.GetDriverByName('GML').CreateDataSource(tmpfile)
        lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
        lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString))
        lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger))
        lyr.CreateField(ogr.FieldDefn('strlistfield', ogr.OFTStringList))
        ds = None

        vl = QgsVectorLayer(tmpfile)
        self.assertTrue(vl.isValid())

        dp = vl.dataProvider()
        fields = dp.fields()
        list_field = fields[fields.lookupField('strlistfield')]
        self.assertEqual(list_field.type(), QVariant.List)
        self.assertEqual(list_field.typeName(), 'StringList')
        self.assertEqual(list_field.subType(), QVariant.String)
    def testHstore(self):
        vl = QgsVectorLayer('%s table="qgis_test"."dict" sql=' % (self.dbconn), "testhstore", "postgres")
        self.assertTrue(vl.isValid())

        fields = vl.dataProvider().fields()
        self.assertEqual(fields.at(fields.indexFromName('value')).type(), QVariant.Map)

        f = next(vl.getFeatures(QgsFeatureRequest()))

        value_idx = vl.fields().lookupField('value')
        self.assertIsInstance(f.attributes()[value_idx], dict)
        self.assertEqual(f.attributes()[value_idx], {'a': 'b', '1': '2'})

        new_f = QgsFeature(vl.fields())
        new_f['pk'] = NULL
        new_f['value'] = {'simple': '1', 'doubleQuote': '"y"', 'quote': "'q'", 'backslash': '\\'}
        r, fs = vl.dataProvider().addFeatures([new_f])
        self.assertTrue(r)
        new_pk = fs[0]['pk']
        self.assertNotEqual(new_pk, NULL, fs[0].attributes())

        try:
            read_back = vl.getFeature(new_pk)
            self.assertEqual(read_back['pk'], new_pk)
            self.assertEqual(read_back['value'], new_f['value'])
        finally:
            self.assertTrue(vl.startEditing())
            self.assertTrue(vl.deleteFeatures([new_pk]))
            self.assertTrue(vl.commitChanges())
        def _test_db(testPath):
            vl = QgsVectorLayer(testPath, 'test', 'spatialite')
            self.assertTrue(vl.isValid())

            f = next(vl.getFeatures())
            self.assertTrue(f.isValid())
            fid = f.id()
            self.assertTrue(fid > 0)
            self.assertTrue(vl.getFeature(fid).isValid())
            f2 = next(vl.getFeatures(QgsFeatureRequest().setFilterFid(fid)))
            self.assertTrue(f2.isValid())
            self.assertEqual(f2.id(), f.id())
            self.assertEqual(f2.geometry().asWkt(), f.geometry().asWkt())

            for f in vl.getFeatures():
                self.assertTrue(f.isValid())
                self.assertTrue(vl.getFeature(f.id()).isValid())
                self.assertEqual(vl.getFeature(f.id()).id(), f.id())
    def test_arrays_write(self):
        """Test writing of layers with arrays"""
        l = QgsVectorLayer("dbname=%s table=test_arrays_write (geometry)" % self.dbname, "test_arrays", "spatialite")
        self.assertTrue(l.isValid())

        new_f = QgsFeature(l.fields())
        new_f['id'] = 2
        new_f['array'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash']
        new_f['strings'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash']
        new_f['ints'] = [1, 2, 3, 4]
        new_f['reals'] = [1e67, 1e-56]
        r, fs = l.dataProvider().addFeatures([new_f])
        self.assertTrue(r)

        read_back = l.getFeature(new_f['id'])
        self.assertEqual(read_back['id'], new_f['id'])
        self.assertEqual(read_back['array'], new_f['array'])
        self.assertEqual(read_back['strings'], new_f['strings'])
        self.assertEqual(read_back['ints'], new_f['ints'])
        self.assertEqual(read_back['reals'], new_f['reals'])

        new_f = QgsFeature(l.fields())
        new_f['id'] = 3
        new_f['array'] = [1, 1.2345, '"doubleQuote"', "'quote'", 'back\\slash']
        new_f['strings'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash']
        new_f['ints'] = [1, 2, 3, 4]
        new_f['reals'] = [1e67, 1e-56]
        r, fs = l.dataProvider().addFeatures([new_f])
        self.assertTrue(r)

        read_back = l.getFeature(new_f['id'])
        self.assertEqual(read_back['id'], new_f['id'])
        self.assertEqual(read_back['array'], new_f['array'])
        self.assertEqual(read_back['strings'], new_f['strings'])
        self.assertEqual(read_back['ints'], new_f['ints'])
        self.assertEqual(read_back['reals'], new_f['reals'])

        read_back = l.getFeature(new_f['id'])
    def test_zm(self):
        """Test Z dimension and M value"""
        l = QgsVectorLayer("dbname=%s table='test_z' (geometry) key='id'" % self.dbname, "test_z", "spatialite")
        self.assertTrue(l.isValid())
        self.assertTrue(QgsWkbTypes.hasZ(l.wkbType()))
        feature = l.getFeature(1)
        geom = feature.geometry().constGet()
        self.assertEqual(geom.z(), 1.0)

        l = QgsVectorLayer("dbname=%s table='test_m' (geometry) key='id'" % self.dbname, "test_m", "spatialite")
        self.assertTrue(l.isValid())
        self.assertTrue(QgsWkbTypes.hasM(l.wkbType()))
        feature = l.getFeature(1)
        geom = feature.geometry().constGet()
        self.assertEqual(geom.m(), 1.0)

        l = QgsVectorLayer("dbname=%s table='test_zm' (geometry) key='id'" % self.dbname, "test_zm", "spatialite")
        self.assertTrue(l.isValid())
        self.assertTrue(QgsWkbTypes.hasZ(l.wkbType()))
        self.assertTrue(QgsWkbTypes.hasM(l.wkbType()))
        feature = l.getFeature(1)
        geom = feature.geometry().constGet()
        self.assertEqual(geom.z(), 1.0)
        self.assertEqual(geom.m(), 1.0)
    def testWriteWithBoolField(self):

        # init connection string
        dbconn = 'dbname=\'qgis_test\''
        if 'QGIS_PGTEST_DB' in os.environ:
            dbconn = os.environ['QGIS_PGTEST_DB']

        # create a vector layer
        vl = QgsVectorLayer('{} table="qgis_test"."boolean_table" sql='.format(dbconn), "testbool", "postgres")
        self.assertTrue(vl.isValid())

        # check that 1 of its fields is a bool
        fields = vl.fields()
        self.assertEqual(fields.at(fields.indexFromName('fld1')).type(), QVariant.Bool)

        # write a gpkg package with a bool field
        crs = QgsCoordinateReferenceSystem()
        crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
        filename = os.path.join(str(QDir.tempPath()), 'with_bool_field')
        rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(vl,
                                                             filename,
                                                             'utf-8',
                                                             crs,
                                                             'GPKG')

        self.assertEqual(rc, QgsVectorFileWriter.NoError)

        # open the resulting geopackage
        vl = QgsVectorLayer(filename + '.gpkg', '', 'ogr')
        self.assertTrue(vl.isValid())
        fields = vl.fields()

        # test type of converted field
        idx = fields.indexFromName('fld1')
        self.assertEqual(fields.at(idx).type(), QVariant.Bool)

        # test values
        self.assertEqual(vl.getFeature(1).attributes()[idx], 1)
        self.assertEqual(vl.getFeature(2).attributes()[idx], 0)

        del vl
        os.unlink(filename + '.gpkg')
    def test_arrays(self):
        """Test loading of layers with arrays"""
        l = QgsVectorLayer("dbname=%s table=test_arrays (geometry)" % self.dbname, "test_arrays", "spatialite")
        self.assertTrue(l.isValid())

        features = [f for f in l.getFeatures()]
        self.assertEqual(len(features), 1)

        strings_field = l.fields().field('strings')
        self.assertEqual(strings_field.typeName(), 'jsonstringlist')
        self.assertEqual(strings_field.type(), QVariant.StringList)
        self.assertEqual(strings_field.subType(), QVariant.String)
        strings = features[0].attributes()[1]
        self.assertEqual(strings, ['toto', 'tutu'])

        ints_field = l.fields().field('ints')
        self.assertEqual(ints_field.typeName(), 'jsonintegerlist')
        self.assertEqual(ints_field.type(), QVariant.List)
        self.assertEqual(ints_field.subType(), QVariant.LongLong)
        ints = features[0].attributes()[2]
        self.assertEqual(ints, [1, -2, 724562])

        reals_field = l.fields().field('reals')
        self.assertEqual(reals_field.typeName(), 'jsonreallist')
        self.assertEqual(reals_field.type(), QVariant.List)
        self.assertEqual(reals_field.subType(), QVariant.Double)
        reals = features[0].attributes()[3]
        self.assertEqual(reals, [1.0, -232567.22])

        new_f = QgsFeature(l.fields())
        new_f['id'] = 2
        new_f['strings'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash']
        new_f['ints'] = [1, 2, 3, 4]
        new_f['reals'] = [1e67, 1e-56]
        r, fs = l.dataProvider().addFeatures([new_f])
        self.assertTrue(r)

        read_back = l.getFeature(new_f['id'])
        self.assertEqual(read_back['id'], new_f['id'])
        self.assertEqual(read_back['strings'], new_f['strings'])
        self.assertEqual(read_back['ints'], new_f['ints'])
        self.assertEqual(read_back['reals'], new_f['reals'])
    def testWriteWithLongLongField(self):
        ml = QgsVectorLayer('NoGeometry?crs=epsg:4326&field=fldlonglong:long',
                            'test2', 'memory')
        provider = ml.dataProvider()
        feat = QgsFeature()
        feat.setAttributes([2262000000])
        provider.addFeatures([feat])

        filename = os.path.join(str(QDir.tempPath()), 'with_longlong_field')
        crs = QgsCoordinateReferenceSystem()
        crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
        rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(ml, filename, 'utf-8', crs, 'GPKG')

        # open the resulting geopackage
        vl = QgsVectorLayer(filename + '.gpkg', '', 'ogr')
        self.assertTrue(vl.isValid())

        # test values
        idx = vl.fields().indexFromName('fldlonglong')
        self.assertEqual(vl.getFeature(1).attributes()[idx], 2262000000)
Exemple #13
0
    def calcQneatInterpolation(self, iso_pointcloud_featurelist, resolution,
                               interpolation_raster_path):
        #prepare spatial index
        uri = 'PointM?crs={}&field=vertex_id:int(254)&field=cost:double(254,7)&key=vertex_id&index=yes'.format(
            self.AnalysisCrs.authid())

        mIsoPointcloud = QgsVectorLayer(uri, "mIsoPointcloud_layer", "memory")
        mIsoPointcloud_provider = mIsoPointcloud.dataProvider()
        mIsoPointcloud_provider.addFeatures(iso_pointcloud_featurelist,
                                            QgsFeatureSink.FastInsert)

        #implement spatial index for lines (closest line, etc...)
        spt_idx = QgsSpatialIndex(
            mIsoPointcloud.getFeatures(QgsFeatureRequest()), self.feedback)

        #prepare numpy coordinate grids
        NoData_value = -9999
        raster_rectangle = mIsoPointcloud.extent()

        #top left point
        xmin = raster_rectangle.xMinimum()
        ymin = raster_rectangle.yMinimum()
        xmax = raster_rectangle.xMaximum()
        ymax = raster_rectangle.yMaximum()

        cols = int((xmax - xmin) / resolution)
        rows = int((ymax - ymin) / resolution)

        output_interpolation_raster = gdal.GetDriverByName('GTiff').Create(
            interpolation_raster_path, cols, rows, 1, gdal.GDT_Float64)
        output_interpolation_raster.SetGeoTransform(
            (xmin, resolution, 0, ymax, 0, -resolution))

        band = output_interpolation_raster.GetRasterBand(1)
        band.SetNoDataValue(NoData_value)

        #initialize zero array with 2 dimensions (according to rows and cols)
        raster_data = zeros(shape=(rows, cols))

        #compute raster cell MIDpoints
        x_pos = linspace(xmin + (resolution / 2), xmax - (resolution / 2),
                         raster_data.shape[1])
        y_pos = linspace(ymax - (resolution / 2), ymin + (resolution / 2),
                         raster_data.shape[0])
        x_grid, y_grid = meshgrid(x_pos, y_pos)

        self.feedback.pushInfo(
            '[QNEAT3Network][calcQneatInterpolation] Beginning with interpolation'
        )
        total_work = rows * cols
        counter = 0

        self.feedback.pushInfo(
            '[QNEAT3Network][calcQneatInterpolation] Total workload: {} cells'.
            format(total_work))
        self.feedback.setProgress(0)
        for i in range(rows):
            for j in range(cols):
                current_pixel_midpoint = QgsPointXY(x_grid[i, j], y_grid[i, j])

                nearest_vertex_fid = spt_idx.nearestNeighbor(
                    current_pixel_midpoint, 1)[0]

                nearest_feature = mIsoPointcloud.getFeature(nearest_vertex_fid)

                nearest_vertex = self.network.vertex(
                    nearest_feature['vertex_id'])

                edges = nearest_vertex.incomingEdges(
                ) + nearest_vertex.outgoingEdges()

                vertex_found = False
                nearest_counter = 2
                while vertex_found == False:
                    n_nearest_feature_fid = spt_idx.nearestNeighbor(
                        current_pixel_midpoint,
                        nearest_counter)[nearest_counter - 1]
                    n_nearest_feature = mIsoPointcloud.getFeature(
                        n_nearest_feature_fid)
                    n_nearest_vertex_id = n_nearest_feature['vertex_id']

                    for edge_id in edges:
                        from_vertex_id = self.network.edge(
                            edge_id).fromVertex()
                        to_vertex_id = self.network.edge(edge_id).toVertex()

                        if n_nearest_vertex_id == from_vertex_id:
                            vertex_found = True
                            vertex_type = "from_vertex"
                            from_point = n_nearest_feature.geometry().asPoint()
                            from_vertex_cost = n_nearest_feature['cost']
                        if n_nearest_vertex_id == to_vertex_id:
                            vertex_found = True
                            vertex_type = "to_vertex"
                            to_point = n_nearest_feature.geometry().asPoint()
                            to_vertex_cost = n_nearest_feature['cost']

                    nearest_counter = nearest_counter + 1
                    """
                    if nearest_counter == 5:
                        vertex_found = True
                        vertex_type = "end_vertex"
                    """

                if vertex_type == "from_vertex":
                    nearest_edge_geometry = QgsGeometry().fromPolylineXY(
                        [from_point, nearest_vertex.point()])
                    res = nearest_edge_geometry.closestSegmentWithContext(
                        current_pixel_midpoint)
                    segment_point = res[
                        1]  #[0: distance, 1: point, 2: left_of, 3: epsilon for snapping]
                    dist_to_segment = segment_point.distance(
                        current_pixel_midpoint)
                    dist_edge = from_point.distance(segment_point)
                    #self.feedback.pushInfo("dist_to_segment = {}".format(dist_to_segment))
                    #self.feedback.pushInfo("dist_on_edge = {}".format(dist_edge))
                    #self.feedback.pushInfo("cost = {}".format(from_vertex_cost))
                    pixel_cost = from_vertex_cost + dist_edge + dist_to_segment
                    raster_data[i, j] = pixel_cost
                elif vertex_type == "to_vertex":
                    nearest_edge_geometry = QgsGeometry().fromPolylineXY(
                        [nearest_vertex.point(), to_point])
                    res = nearest_edge_geometry.closestSegmentWithContext(
                        current_pixel_midpoint)
                    segment_point = res[
                        1]  #[0: distance, 1: point, 2: left_of, 3: epsilon for snapping]
                    dist_to_segment = segment_point.distance(
                        current_pixel_midpoint)
                    dist_edge = to_point.distance(segment_point)
                    #self.feedback.pushInfo("dist_to_segment = {}".format(dist_to_segment))
                    #self.feedback.pushInfo("dist_on_edge = {}".format(dist_edge))
                    #self.feedback.pushInfo("cost = {}".format(from_vertex_cost))
                    pixel_cost = to_vertex_cost + dist_edge + dist_to_segment
                    raster_data[i, j] = pixel_cost
                else:
                    pixel_cost = -99999  #nearest_feature['cost'] + (nearest_vertex.point().distance(current_pixel_midpoint))
                """
                nearest_feature_pointxy = nearest_feature.geometry().asPoint()
                nearest_feature_cost = nearest_feature['cost']
                
                dist_to_vertex = current_pixel_midpoint.distance(nearest_feature_pointxy)
                #implement time cost
                pixel_cost = dist_to_vertex + nearest_feature_cost
                
                raster_data[i,j] = pixel_cost
                """
                counter = counter + 1
                if counter % 1000 == 0:
                    self.feedback.pushInfo(
                        "[QNEAT3Network][calcQneatInterpolation] Interpolated {} cells..."
                        .format(counter))
                self.feedback.setProgress((counter / total_work) * 100)

        band.WriteArray(raster_data)
        outRasterSRS = osr.SpatialReference()
        outRasterSRS.ImportFromWkt(self.AnalysisCrs.toWkt())
        output_interpolation_raster.SetProjection(outRasterSRS.ExportToWkt())
        band.FlushCache()
        def _test(autoTransaction):
            """Test buffer methods within and without transactions

            - create a feature
            - save
            - retrieve the feature
            - change geom and attrs
            - test changes are seen in the buffer
            """

            def _check_feature(wkt):

                f = next(layer_a.getFeatures())
                self.assertEqual(f.geometry().asWkt().upper(), wkt)
                f = list(buffer.addedFeatures().values())[0]
                self.assertEqual(f.geometry().asWkt().upper(), wkt)

            ml = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer', 'test', 'memory')
            self.assertTrue(ml.isValid())

            d = QTemporaryDir()
            options = QgsVectorFileWriter.SaveVectorOptions()
            options.driverName = 'GPKG'
            options.layerName = 'layer_a'
            err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options)

            self.assertEqual(err, QgsVectorFileWriter.NoError)
            self.assertTrue(os.path.isfile(os.path.join(d.path(), 'transaction_test.gpkg')))

            options.layerName = 'layer_b'
            options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer
            err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options)

            layer_a = QgsVectorLayer(os.path.join(d.path(), 'transaction_test.gpkg|layername=layer_a'))

            self.assertTrue(layer_a.isValid())

            project = QgsProject()
            project.setAutoTransaction(autoTransaction)
            project.addMapLayers([layer_a])

            ###########################################
            # Tests with a new feature

            self.assertTrue(layer_a.startEditing())
            buffer = layer_a.editBuffer()

            f = QgsFeature(layer_a.fields())
            f.setAttribute('int', 123)
            f.setGeometry(QgsGeometry.fromWkt('point(7 45)'))
            self.assertTrue(layer_a.addFeatures([f]))

            _check_feature('POINT (7 45)')

            # Need to fetch the feature because its ID is NULL (-9223372036854775808)
            f = next(layer_a.getFeatures())

            self.assertEqual(len(buffer.addedFeatures()), 1)
            layer_a.undoStack().undo()
            self.assertEqual(len(buffer.addedFeatures()), 0)
            layer_a.undoStack().redo()
            self.assertEqual(len(buffer.addedFeatures()), 1)
            f = list(buffer.addedFeatures().values())[0]
            self.assertEqual(f.attribute('int'), 123)

            # Now change attribute
            self.assertEqual(buffer.changedAttributeValues(), {})
            layer_a.changeAttributeValue(f.id(), 1, 321)

            self.assertEqual(len(buffer.addedFeatures()), 1)
            # This is surprising: because it was a new feature it has been changed directly
            self.assertEqual(buffer.changedAttributeValues(), {})
            f = list(buffer.addedFeatures().values())[0]
            self.assertEqual(f.attribute('int'), 321)

            layer_a.undoStack().undo()
            self.assertEqual(buffer.changedAttributeValues(), {})
            f = list(buffer.addedFeatures().values())[0]
            self.assertEqual(f.attribute('int'), 123)
            f = next(layer_a.getFeatures())
            self.assertEqual(f.attribute('int'), 123)

            # Change geometry
            f = next(layer_a.getFeatures())
            self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)')))

            _check_feature('POINT (9 43)')
            self.assertEqual(buffer.changedGeometries(), {})

            layer_a.undoStack().undo()

            _check_feature('POINT (7 45)')
            self.assertEqual(buffer.changedGeometries(), {})

            self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)')))
            _check_feature('POINT (9 43)')

            self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(10 44)')))
            _check_feature('POINT (10 44)')

            # This is anothr surprise: geometry edits get collapsed into a single
            # one because they have the same hardcoded id
            layer_a.undoStack().undo()
            _check_feature('POINT (7 45)')

            self.assertTrue(layer_a.commitChanges())

            ###########################################
            # Tests with the existing feature

            # Get the feature
            f = next(layer_a.getFeatures())
            self.assertTrue(f.isValid())
            self.assertEqual(f.attribute('int'), 123)
            self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)')

            self.assertTrue(layer_a.startEditing())
            layer_a.changeAttributeValue(f.id(), 1, 321)
            buffer = layer_a.editBuffer()
            self.assertEqual(buffer.changedAttributeValues(), {1: {1: 321}})
            layer_a.undoStack().undo()
            self.assertEqual(buffer.changedAttributeValues(), {})

            # Change geometry
            self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)')))
            f = next(layer_a.getFeatures())
            self.assertEqual(f.geometry().asWkt().upper(), 'POINT (9 43)')
            self.assertEqual(buffer.changedGeometries()[1].asWkt().upper(), 'POINT (9 43)')
            layer_a.undoStack().undo()
            self.assertEqual(buffer.changedGeometries(), {})
            f = next(layer_a.getFeatures())

            self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)')
            self.assertEqual(buffer.changedGeometries(), {})

            # Delete an existing feature
            self.assertTrue(layer_a.deleteFeature(f.id()))
            with self.assertRaises(StopIteration):
                next(layer_a.getFeatures())
            self.assertEqual(buffer.deletedFeatureIds(), [f.id()])

            layer_a.undoStack().undo()
            self.assertTrue(layer_a.getFeature(f.id()).isValid())
            self.assertEqual(buffer.deletedFeatureIds(), [])

            ###########################################
            # Test delete

            # Delete a new feature
            f = QgsFeature(layer_a.fields())
            f.setAttribute('int', 555)
            f.setGeometry(QgsGeometry.fromWkt('point(8 46)'))
            self.assertTrue(layer_a.addFeatures([f]))
            f = [f for f in layer_a.getFeatures() if f.attribute('int') == 555][0]
            self.assertTrue(f.id() in buffer.addedFeatures())
            self.assertTrue(layer_a.deleteFeature(f.id()))
            self.assertFalse(f.id() in buffer.addedFeatures())
            self.assertFalse(f.id() in buffer.deletedFeatureIds())

            layer_a.undoStack().undo()
            self.assertTrue(f.id() in buffer.addedFeatures())

            ###########################################
            # Add attribute

            field = QgsField('attr1', QVariant.String)
            self.assertTrue(layer_a.addAttribute(field))
            self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1)
            self.assertEqual(buffer.addedAttributes(), [field])

            layer_a.undoStack().undo()
            self.assertEqual(layer_a.fields().lookupField(field.name()), -1)
            self.assertEqual(buffer.addedAttributes(), [])

            layer_a.undoStack().redo()
            self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1)
            self.assertEqual(buffer.addedAttributes(), [field])

            self.assertTrue(layer_a.commitChanges())

            ###########################################
            # Remove attribute

            self.assertTrue(layer_a.startEditing())
            buffer = layer_a.editBuffer()

            attr_idx = layer_a.fields().lookupField(field.name())
            self.assertNotEqual(attr_idx, -1)

            self.assertTrue(layer_a.deleteAttribute(attr_idx))
            self.assertEqual(buffer.deletedAttributeIds(), [2])
            self.assertEqual(layer_a.fields().lookupField(field.name()), -1)

            layer_a.undoStack().undo()
            self.assertEqual(buffer.deletedAttributeIds(), [])
            self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx)

            layer_a.undoStack().redo()
            self.assertEqual(buffer.deletedAttributeIds(), [2])
            self.assertEqual(layer_a.fields().lookupField(field.name()), -1)

            self.assertTrue(layer_a.rollBack())

            ###########################################
            # Rename attribute

            self.assertTrue(layer_a.startEditing())

            attr_idx = layer_a.fields().lookupField(field.name())
            self.assertNotEqual(attr_idx, -1)

            self.assertEqual(layer_a.fields().lookupField('new_name'), -1)
            self.assertTrue(layer_a.renameAttribute(attr_idx, 'new_name'))
            self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx)

            layer_a.undoStack().undo()
            self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx)
            self.assertEqual(layer_a.fields().lookupField('new_name'), -1)

            layer_a.undoStack().redo()
            self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx)
            self.assertEqual(layer_a.fields().lookupField(field.name()), -1)
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        if source is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))

        name_field_name = self.parameterAsString(parameters, self.NAME_FIELD,
                                                 context)
        elevation_field_name = self.parameterAsString(parameters,
                                                      self.ELEVATION_FIELD,
                                                      context)
        name_field_index = source.fields().lookupField(name_field_name)
        elevation_field_index = source.fields().lookupField(
            elevation_field_name)

        request = QgsFeatureRequest()
        request.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326'),
                                  context.transformContext())
        expression_string = self.parameterAsString(parameters,
                                                   self.ORDERBY_EXPRESSION,
                                                   context)
        if expression_string:
            expression = QgsExpression(expression_string)
            if expression.hasParserError():
                raise QgsProcessingException(expression.parserErrorString())
            request.addOrderBy(expression_string)

        departure_point = QgsPointXY()
        destination_point = QgsPointXY()
        user_points = ''

        total = 100.0 / source.featureCount() if source.featureCount() else 0
        features = source.getFeatures(request)
        for current, feature in enumerate(features):
            if feedback.isCanceled():
                break
            if not feature.hasGeometry():
                continue
            point = feature.geometry().asPoint()

            if departure_point.isEmpty():
                departure_point = point
            destination_point = point

            name = 'UNTITLED'
            if name_field_index >= 0:
                name = feature[name_field_index]
                name = re.sub('[^0-9A-Za-z_]', '', re.sub('\s+', '_', name))

            elevation = 1000.0
            if elevation_field_index >= 0:
                elevation = feature[elevation_field_index]
            user_points += '        <ATCWaypoint id="{}">\n            <ATCWaypointType>User</ATCWaypointType>\n            <WorldPosition>{}</WorldPosition>\n        </ATCWaypoint>\n'.format(
                name, self.formattedCoordinateElevation(point, elevation))
            feedback.setProgress(int(current * total))

        if departure_point.isEmpty():
            raise QgsProcessingException('Error: departure point is missing')
        if destination_point.isEmpty():
            raise QgsProcessingException('Error: destination point is missing')

        strips = QgsVectorLayer(
            os.path.join(os.path.dirname(__file__), 'data', 'strips.gpkg'),
            'strips')
        index = QgsSpatialIndex(strips.getFeatures())

        icao_index = strips.fields().lookupField('icao')
        name_short_index = strips.fields().lookupField('nameshort')

        departure_airport = self.parameterAsString(parameters,
                                                   self.DEPARTURE_AIRPORT,
                                                   context)
        if departure_airport:
            feature = QgsFeature()
            expression = QgsExpression(
                "icao ILIKE '{}'".format(departure_airport))
            strips.getFeatures(
                QgsFeatureRequest(expression)).nextFeature(feature)
            if feature:
                departure_point = feature.geometry().asPoint()
            else:
                raise QgsProcessingException(
                    'Error: custom departure airport ICAO ID not found')

        destination_airport = self.parameterAsString(parameters,
                                                     self.DESTINATION_AIRPORT,
                                                     context)
        if destination_airport:
            feature = QgsFeature()
            expression = QgsExpression(
                "icao ILIKE '{}'".format(destination_airport))
            strips.getFeatures(
                QgsFeatureRequest(expression)).nextFeature(feature)
            if feature:
                destination_point = feature.geometry().asPoint()
            else:
                raise QgsProcessingException(
                    'Error: custom destination airport ICAO ID not found')

        departure = ''
        departure_header = ''
        destination = ''
        destination_header = ''
        if not departure_point.isEmpty():
            departure_id = index.nearestNeighbor(departure_point)
            feature = strips.getFeature(departure_id[0])
            point = feature.geometry().asPoint()
            elevation = 50.0
            departure = '        <ATCWaypoint id="{}">\n            <ATCWaypointType>Airport</ATCWaypointType>\n            <WorldPosition>{}</WorldPosition>\n            <RunwayNumberFP>1</RunwayNumberFP>\n            <ICAO>\n                <ICAOIdent>{}</ICAOIdent>\n            </ICAO>\n        </ATCWaypoint>\n'.format(
                feature[icao_index],
                self.formattedCoordinateElevation(point, elevation),
                feature[icao_index])
            departure_header = '        <DepartureID>{}</DepartureID>\n        <DepartureLLA>{}</DepartureLLA>\n        <DepartureName>{}</DepartureName>\n'.format(
                feature[icao_index],
                self.formattedCoordinateElevation(point, elevation),
                feature[name_short_index])

        if not destination_point.isEmpty():
            destination_id = index.nearestNeighbor(destination_point)
            feature = strips.getFeature(destination_id[0])
            point = feature.geometry().asPoint()
            elevation = 50.0
            destination = '        <ATCWaypoint id="{}">\n            <ATCWaypointType>Airport</ATCWaypointType>\n            <WorldPosition>{}</WorldPosition>\n            <RunwayNumberFP>1</RunwayNumberFP>\n            <ICAO>\n                <ICAOIdent>{}</ICAOIdent>\n            </ICAO>\n        </ATCWaypoint>\n'.format(
                feature[icao_index],
                self.formattedCoordinateElevation(point, elevation),
                feature[icao_index])
            destination_header = '        <DestinationID>{}</DestinationID>\n        <DestinationLLA>{}</DestinationLLA>\n        <DestinationName>{}</DestinationName>\n'.format(
                feature[icao_index],
                self.formattedCoordinateElevation(point, elevation),
                feature[name_short_index])

        title = self.parameterAsString(parameters, self.TITLE, context)

        plan_file_path = self.parameterAsString(parameters, self.OUTPUT,
                                                context)
        plan_file = open(plan_file_path, 'w')
        plan_file.write(
            '<?xml version="1.0" encoding="UTF-8"?>\n\n<SimBase.Document Type="AceXML" version="1,0">\n    <Descr>AceXML Document</Descr>\n    <FlightPlan.FlightPlan>\n        <Title>{}</Title>\n        <FPType>IFR</FPType>\n        <RouteType>LowAlt</RouteType>\n        <CruisingAlt>11000.000</CruisingAlt>\n'
            .format(title))
        plan_file.write(departure_header + destination_header)
        plan_file.write(
            '        <Descr>{}</Descr>\n        <AppVersion>\n            <AppVersionMajor>11</AppVersionMajor>\n            <AppVersionBuild>282174</AppVersionBuild>\n        </AppVersion>\n'
            .format(title))
        plan_file.write(departure + user_points + destination)
        plan_file.write('    </FlightPlan.FlightPlan>\n</SimBase.Document>\n')
        plan_file.close()

        return {self.OUTPUT: plan_file_path}
Exemple #16
0
    def testTypeValidation(self):
        """Test that incompatible types in attributes raise errors"""

        vl = QgsVectorLayer(
            'Point?crs=epsg:4326&field=int:integer',
            'test', 'memory')
        self.assertTrue(vl.isValid())
        invalid = QgsFeature(vl.fields())
        invalid.setAttribute('int', 'A string')
        invalid.setGeometry(QgsGeometry.fromWkt('point(9 45)'))
        self.assertTrue(vl.startEditing())
        # Validation happens on commit
        self.assertTrue(vl.addFeatures([invalid]))
        self.assertFalse(vl.commitChanges())
        self.assertTrue(vl.rollBack())
        self.assertFalse(vl.hasFeatures())

        # Add a valid feature
        valid = QgsFeature(vl.fields())
        valid.setAttribute('int', 123)
        self.assertTrue(vl.startEditing())
        self.assertTrue(vl.addFeatures([valid]))
        self.assertTrue(vl.commitChanges())
        self.assertEqual(vl.featureCount(), 1)

        f = vl.getFeature(1)
        self.assertEqual(f.attribute('int'), 123)

        # Add both
        vl = QgsVectorLayer(
            'Point?crs=epsg:4326&field=int:integer',
            'test', 'memory')
        self.assertEqual(vl.featureCount(), 0)
        self.assertTrue(vl.startEditing())
        self.assertTrue(vl.addFeatures([valid, invalid]))
        self.assertFalse(vl.commitChanges())
        self.assertEqual(vl.featureCount(), 2)
        self.assertTrue(vl.rollBack())
        self.assertEqual(vl.featureCount(), 0)

        # Add both swapped
        vl = QgsVectorLayer(
            'Point?crs=epsg:4326&field=int:integer',
            'test', 'memory')
        self.assertTrue(vl.startEditing())
        self.assertTrue(vl.addFeatures([invalid, valid]))
        self.assertFalse(vl.commitChanges())
        self.assertEqual(vl.featureCount(), 2)
        self.assertTrue(vl.rollBack())
        self.assertEqual(vl.featureCount(), 0)

        # Change attribute value
        vl = QgsVectorLayer(
            'Point?crs=epsg:4326&field=int:integer',
            'test', 'memory')
        self.assertTrue(vl.startEditing())
        self.assertTrue(vl.addFeatures([valid]))
        self.assertTrue(vl.commitChanges())
        self.assertTrue(vl.startEditing())
        self.assertTrue(vl.changeAttributeValue(1, 0, 'A string'))
        self.assertFalse(vl.commitChanges())
        f = vl.getFeature(1)
        self.assertEqual(f.attribute('int'), 'A string')
        self.assertTrue(vl.rollBack())

        f = vl.getFeature(1)
        self.assertEqual(f.attribute('int'), 123)

        # Change attribute values
        vl = QgsVectorLayer(
            'Point?crs=epsg:4326&field=int:integer',
            'test', 'memory')
        self.assertTrue(vl.startEditing())
        self.assertTrue(vl.addFeatures([valid]))
        self.assertTrue(vl.commitChanges())
        self.assertTrue(vl.startEditing())
        self.assertTrue(vl.changeAttributeValues(1, {0: 'A string'}))
        self.assertFalse(vl.commitChanges())
        f = vl.getFeature(1)
        self.assertEqual(f.attribute('int'), 'A string')
        self.assertTrue(vl.rollBack())

        f = vl.getFeature(1)
        self.assertEqual(f.attribute('int'), 123)

        ##############################################
        # Test direct data provider calls

        # No rollback (old behavior)
        vl = QgsVectorLayer(
            'Point?crs=epsg:4326&field=int:integer',
            'test', 'memory')
        dp = vl.dataProvider()
        self.assertFalse(dp.addFeatures([valid, invalid])[0])
        self.assertEqual([f.attributes() for f in dp.getFeatures()], [[123]])
        f = vl.getFeature(1)
        self.assertEqual(f.attribute('int'), 123)

        # Roll back
        vl = QgsVectorLayer(
            'Point?crs=epsg:4326&field=int:integer',
            'test', 'memory')
        dp = vl.dataProvider()
        self.assertFalse(dp.addFeatures([valid, invalid], QgsFeatureSink.RollBackOnErrors)[0])
        self.assertFalse(dp.hasFeatures())

        # Expected behavior for changeAttributeValues is to always roll back
        self.assertTrue(dp.addFeatures([valid])[0])
        self.assertFalse(dp.changeAttributeValues({1: {0: 'A string'}}))
        f = vl.getFeature(1)
        self.assertEqual(f.attribute('int'), 123)
    def testObjectIdDifferentName(self):
        """ Test that object id fields not named OBJECTID work correctly """

        endpoint = self.basetestpath + '/oid_fake_qgis_http_endpoint'
        with open(sanitize(endpoint, '?f=json'), 'wb') as f:
            f.write("""
        {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
        "QGIS Provider Test Layer.\n","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[],
        "minScale":72225,"maxScale":0,
        "defaultVisibility":true,
        "extent":{"xmin":-71.123,"ymin":66.33,"xmax":-65.32,"ymax":78.3,
        "spatialReference":{"wkid":4326,"latestWkid":4326}},
        "hasAttachments":false,"htmlPopupType":"esriServerHTMLPopupTypeAsHTMLText",
        "displayField":"LABEL","typeIdField":null,
        "fields":[{"name":"OBJECTID1","type":"esriFieldTypeOID","alias":"OBJECTID","domain":null},
        {"name":"pk","type":"esriFieldTypeInteger","alias":"pk","domain":null},
        {"name":"cnt","type":"esriFieldTypeInteger","alias":"cnt","domain":null}],
        "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
        "capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true,
        "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
        "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""".encode(
                'UTF-8'))

        with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f:
            f.write("""
        {
         "objectIdFieldName": "OBJECTID1",
         "objectIds": [
          5,
          3,
          1,
          2,
          4
         ]
        }
        """.encode('UTF-8'))

        with open(sanitize(endpoint, '/query?f=json&objectIds=5,3,1,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=OBJECTID1,pk,cnt&returnM=false&returnZ=false'), 'wb') as f:
            f.write("""
        {
         "displayFieldName": "LABEL",
         "geometryType": "esriGeometryPoint",
         "spatialReference": {
          "wkid": 4326,
          "latestWkid": 4326
         },
         "fields":[{"name":"OBJECTID1","type":"esriFieldTypeOID","alias":"OBJECTID1","domain":null},
          {"name":"pk","type":"esriFieldTypeInteger","alias":"pk","domain":null},
          {"name":"cnt","type":"esriFieldTypeInteger","alias":"cnt","domain":null},
          {"name":"Shape","type":"esriFieldTypeGeometry","alias":"Shape","domain":null}],
         "features": [
          {
           "attributes": {
            "OBJECTID1": 5,
            "pk": 5,
            "cnt": -200,
            "name": null
           },
           "geometry": {
            "x": -71.123,
            "y": 78.23
           }
          }
         ]
        }""".encode('UTF-8'))

        # Create test layer
        vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver')
        assert vl.isValid()

        f = vl.getFeature(0)
        assert f.isValid()
class TestStratigraphy(utils_for_tests.MidvattenTestPostgisDbSv):
    @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestPostgisNotCreated.mock_instance_settings_database)
    @mock.patch('db_utils.get_postgis_connections', utils_for_tests.MidvattenTestPostgisNotCreated.mock_postgis_connections)
    def create_and_select_vlayer(self):
        self.qgs = QgsApplication([], True)
        self.qgs.initQgis()

        self.midvatten.ms.settingsdict['secplotdrillstop'] = "%berg%"

        dbconnection = db_utils.DbConnectionManager()
        uri = dbconnection.uri
        uri.setDataSource('', 'obs_points', 'geometry', '', 'obsid')
        dbtype = db_utils.get_dbtype(dbconnection.dbtype)
        self.vlayer = QgsVectorLayer(uri.uri(), 'TestLayer', dbtype)

        features = self.vlayer.getFeatures()
        feature_ids = [feature.id() for feature in features]
        self.vlayer.selectByIds(feature_ids)
        print("1. Valid vlayer '{}'".format(self.vlayer.isValid()))
        print("2. feature_ids: " + str(feature_ids))
        print("3. QgsVectorLayer.selectedFeatureIds: " + str(self.vlayer.selectedFeatureIds()))
        print("4. QgsVectorLayer.getSelectedFeatures: " + str([x.id() for x in self.vlayer.getSelectedFeatures()]))
        print("5. QgsVectorLayer.getFeature(): " + str([self.vlayer.getFeature(x).id() for x in feature_ids]))
        print("6. QgsVectorLayer.getFeature() type: " + str([str(type(self.vlayer.getFeature(x))) for x in feature_ids]))
        print("7. QgsVectorLayer.getFeatures(): " + str([x.id() for x in self.vlayer.getFeatures(feature_ids)]))

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestPostgisNotCreated.mock_instance_settings_database)
    @mock.patch('db_utils.get_postgis_connections', utils_for_tests.MidvattenTestPostgisNotCreated.mock_postgis_connections)
    def test_stratigraphy(self, mock_skippopup, mock_messagebar):
        """
        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('1', 5, ST_GeomFromText('POINT(633466 711659)', 3006))''')
        db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('2', 10, ST_GeomFromText('POINT(6720727 016568)', 3006))''')
        db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('3', 20, ST_GeomFromText('POINT(6720728 016569)', 3006))''')
        db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 1, 0, 1, 'sand', 'sand', '3', 'j')''')
        db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 2, 1, 4.5, 'morän', 'morän', '3', 'j')''')

        self.create_and_select_vlayer()

        #print(str(self.vlayer.isValid()))
        #print(str(db_utils.sql_load_fr_db('select * from obs_points')))
        #print(str(db_utils.sql_load_fr_db('select * from stratigraphy')))
        dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict)
        #print(str(mock_messagebar.mock_calls))
        #print(str(mock_skippopup.mock_calls))
        dlg.showSurvey()
        test = utils.anything_to_string_representation(dlg.data)
        test_survey = utils.anything_to_string_representation(repr(dlg.data['1']))
        test_strata = utils.anything_to_string_representation(utils.returnunicode(dlg.data['1'].strata, keep_containers=True))

        assert len(mock_skippopup.mock_calls) == 0
        print(str(mock_messagebar.mock_calls))
        assert len(mock_messagebar.mock_calls) == 0
        assert test == """{"1": SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')}"""
        assert test_survey == '''"SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"'''
        print("test_strata: " + test_strata)
        assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '3', 'morän', 'moran', 1.000000-4.500000)"]'''

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestPostgisNotCreated.mock_instance_settings_database)
    @mock.patch('db_utils.get_postgis_connections', utils_for_tests.MidvattenTestPostgisNotCreated.mock_postgis_connections)
    def test_stratigraphy_with_other_obsid_numbers(self, mock_skippopup, mock_messagebar):
        """

        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('8', 5, ST_GeomFromText('POINT(633466 711659)', 3006))''')
        db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('9', 10, ST_GeomFromText('POINT(6720727 016568)', 3006))''')
        db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('10', 20, ST_GeomFromText('POINT(6720728 016569)', 3006))''')
        db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('8', 1, 0, 1, 'sand', 'sand', '3', 'j')''')
        db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('8', 2, 1, 4.5, 'morän', 'morän', '3', 'j')''')
        self.create_and_select_vlayer()

        dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict)

        dlg.showSurvey()
        print(str(mock_skippopup.mock_calls))
        test = utils.anything_to_string_representation(dlg.data)
        test_survey = utils.anything_to_string_representation(repr(dlg.data['8']))
        test_strata = utils.anything_to_string_representation(
            utils.returnunicode(dlg.data['8'].strata, keep_containers=True))

        assert len(mock_skippopup.mock_calls) == 0
        assert len(mock_messagebar.mock_calls) == 0
        assert test == """{"8": SURVEY('8', 5.000000, '<QgsPointXY: POINT(633466 711659)>')}"""
        assert test_survey == '''"SURVEY('8', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"'''
        print("Test strata " + test_strata)
        assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '3', 'morän', 'moran', 1.000000-4.500000)"]'''

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestPostgisNotCreated.mock_instance_settings_database)
    @mock.patch('db_utils.get_postgis_connections', utils_for_tests.MidvattenTestPostgisNotCreated.mock_postgis_connections)
    def test_stratigraphy_with_string_obsid(self, mock_skippopup, mock_messagebar):
        """
        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('P1', 5, ST_GeomFromText('POINT(633466 711659)', 3006))''')
        db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('P2', 10, ST_GeomFromText('POINT(6720727 016568)', 3006))''')
        db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('P3', 20, ST_GeomFromText('POINT(6720728 016569)', 3006))''')
        db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('P1', 1, 0, 1, 'sand', 'sand', '3', 'j')''')
        db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('P1', 2, 1, 4.5, 'morän', 'morän', '3', 'j')''')

        self.create_and_select_vlayer()

        print(str(self.vlayer.isValid()))
        print(str(db_utils.sql_load_fr_db('select * from obs_points')))
        print(str(db_utils.sql_load_fr_db('select * from stratigraphy')))
        dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict)
        print(str(mock_messagebar.mock_calls))
        print(str(mock_skippopup.mock_calls))
        dlg.showSurvey()
        test = utils.anything_to_string_representation(dlg.data)
        test_survey = utils.anything_to_string_representation(repr(dlg.data['P1']))
        test_strata = utils.anything_to_string_representation(utils.returnunicode(dlg.data['P1'].strata, keep_containers=True))

        assert len(mock_skippopup.mock_calls) == 0
        print(str(mock_messagebar.mock_calls))
        assert len(mock_messagebar.mock_calls) == 0
        assert test == """{"P1": SURVEY('P1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')}"""
        assert test_survey == '''"SURVEY('P1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"'''
        assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '3', 'morän', 'moran', 1.000000-4.500000)"]'''

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestPostgisNotCreated.mock_instance_settings_database)
    @mock.patch('db_utils.get_postgis_connections', utils_for_tests.MidvattenTestPostgisNotCreated.mock_postgis_connections)
    def test_stratigraphy_gap(self, mock_skippopup, mock_messagebar):
        """
        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('1', 5, ST_GeomFromText('POINT(633466 711659)', 3006))''')
        db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('2', 10, ST_GeomFromText('POINT(6720727 016568)', 3006))''')
        db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('3', 20, ST_GeomFromText('POINT(6720728 016569)', 3006))''')
        db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 1, 0, 1, 'sand', 'sand', '3', 'j')''')
        db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 2, 2, 4.5, 'morän', 'morän', '3', 'j')''')

        self.create_and_select_vlayer()

        print(str(self.vlayer.isValid()))
        print(str(db_utils.sql_load_fr_db('select * from obs_points')))
        print(str(db_utils.sql_load_fr_db('select * from stratigraphy')))
        dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict)
        print(str(mock_messagebar.mock_calls))
        print(str(mock_skippopup.mock_calls))
        dlg.showSurvey()
        test = utils.anything_to_string_representation(dlg.data)
        test_survey = utils.anything_to_string_representation(repr(dlg.data['1']))
        test_strata = utils.anything_to_string_representation(utils.returnunicode(dlg.data['1'].strata, keep_containers=True))

        assert len(mock_skippopup.mock_calls) == 0
        assert len(mock_messagebar.mock_calls) == 0
        assert test == """{"1": SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')}"""
        assert test_survey == '''"SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"'''
        assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '', '', '', 1.000000-2.000000)", "strata(3, '3', 'morän', 'moran', 2.000000-4.500000)"]'''

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestPostgisNotCreated.mock_instance_settings_database)
    @mock.patch('db_utils.get_postgis_connections', utils_for_tests.MidvattenTestPostgisNotCreated.mock_postgis_connections)
    def test_stratigraphy_missing_h_gs(self, mock_skippopup, mock_messagebar):
        """
        
        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('1', 5, ST_GeomFromText('POINT(633466 711659)', 3006))''')
        db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, h_toc, geometry) VALUES ('2', NULL, 10, ST_GeomFromText('POINT(6720727 016568)', 3006))''')
        db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, geometry) VALUES ('3', ST_GeomFromText('POINT(6720728 016569)', 3006))''')
        db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 1, 0, 1, 'sand', 'sand', '3', 'j')''')
        db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 2, 1, 4.5, 'morän', 'morän', '3', 'j')''')
        db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('2', 1, 0, 1, 'sand', 'sand', '3', 'j')''')
        db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('2', 2, 1, 4.5, 'morän', 'morän', '3', 'j')''')
        db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('3', 1, 0, 2, 'sand', 'sand', '3', 'j')''')
        db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('3', 2, 2, 6, 'morän', 'morän', '3', 'j')''')
        self.create_and_select_vlayer()

        dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict)

        dlg.showSurvey()
        test = utils.anything_to_string_representation(dlg.data)
        test_survey = utils.anything_to_string_representation(repr(dlg.data['1']))
        test_strata = utils.anything_to_string_representation(utils.returnunicode(dlg.data['1'].strata, keep_containers=True))

        assert len(mock_skippopup.mock_calls) == 1
        print(str(mock_skippopup.mock_calls))
        print(str(mock_messagebar.mock_calls))
        assert mock_skippopup.mock_calls == [mock.call('Warning, h_gs is missing. See messagebar.')]
        assert mock_messagebar.mock_calls == [mock.call.warning(bar_msg="Obsid 2: using h_gs '' failed, using 'h_toc' instead.", duration=90, log_msg='False'),
                                              mock.call.warning(bar_msg="Obsid 3: using h_gs '' failed, using '-1' instead.", duration=90, log_msg='False')]
        print("test: " + test)
        assert test == """{"1": SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>'), "2": SURVEY('2', 10.000000, '<QgsPointXY: POINT(6720727 16568)>'), "3": SURVEY('3', -1.000000, '<QgsPointXY: POINT(6720728 16569)>')}"""
        print("test_survey " + test_survey)
        assert test_survey == '''"SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"'''
        print("Test strata " + test_strata)
        assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '3', 'morän', 'moran', 1.000000-4.500000)"]'''


    def tearDown(self):
        QgsProject.instance().addMapLayer(self.vlayer)
        QgsProject.instance().removeMapLayer(self.vlayer.id())
        super(self.__class__, self).tearDown()
Exemple #19
0
class AddField:
    def __init__(self, parent_widget):
        """This class handle the creation of Fields. This class is also imported
        in the MeanAnalyse class.

        Parameters
        ----------
        parent_widget: GeoDataFarm
        """
        self.iface = parent_widget.iface
        self.tsk_mngr = parent_widget.tsk_mngr
        self.db = parent_widget.db
        self.tr = parent_widget.tr
        self.dock_widget = parent_widget.dock_widget
        self.parent = parent_widget
        self.AFD = AddFieldFileDialog()
        self.field = None
        self.defined_field = ''

    def run(self):
        """Presents the sub widget AddField and connects the different
        buttons to their function"""
        self.AFD.show()
        self.AFD.PBSelectExtent.clicked.connect(self.clicked_define_field)
        self.AFD.PBSave.clicked.connect(self.save)
        self.AFD.PBHelp.clicked.connect(self.help)
        self.AFD.PBQuit.clicked.connect(self.quit)
        self.AFD.exec()
        self.parent.populate.reload_fields()

    def set_widget_connections(self):
        """Function that sets the main widget connections."""
        self.parent.dock_widget.PBAddField.clicked.connect(self.run)
        self.parent.dock_widget.PBRemoveField.clicked.connect(
            self.remove_field)
        self.parent.dock_widget.PBViewFields.clicked.connect(self.view_fields)

    def clicked_define_field(self, ignore_name=True):
        """Creates an empty polygon that's define a field"""
        if ignore_name:
            self.field = QgsVectorLayer("Polygon?crs=epsg:4326", 'Search area',
                                        "memory")
        else:
            name = self.AFD.LEFieldName.text()
            if len(name) == 0:
                QMessageBox.information(
                    None, self.tr('Error:'),
                    self.tr('Field name must be filled in.'))
                return
            self.field = QgsVectorLayer("Polygon?crs=epsg:4326", name,
                                        "memory")

        add_background()
        set_zoom(self.parent.iface, 2)
        self.field.startEditing()
        self.iface.actionAddFeature().trigger()
        QgsProject.instance().addMapLayer(self.field)

    def remove_field(self):
        """Removes a field that the user wants, a check that there are no
        data that is depended on is made."""
        j = -1
        for i in range(self.parent.dock_widget.LWFields.count()):
            j += 1
            item = self.parent.dock_widget.LWFields.item(j)
            if item.checkState() == 2:
                field_name = item.text()
                qm = QMessageBox()
                res = qm.question(
                    None, self.tr('Question'),
                    self.tr("Do you want to delete ") + str(field_name),
                    qm.Yes, qm.No)
                if res == qm.No:
                    continue
                field_names = []
                for tble_type in [
                        'plant', 'ferti', 'spray', 'harvest', 'soil'
                ]:
                    field_names.extend(
                        self.db.execute_and_return(
                            "select field from {type}.manual".format(
                                type=tble_type)))
                sql = """SELECT table_name
               FROM   information_schema.tables 
               WHERE  table_schema = 'other'"""
                for tble_type in self.db.execute_and_return(sql):
                    tbl = tble_type[0]
                    field_names.extend(
                        self.db.execute_and_return(
                            "select field from other.{tbl}".format(tbl=tbl)))
                stop_removing = False
                for row in field_names:
                    if row[0] == field_name:
                        QMessageBox.information(
                            None, self.tr('Error'),
                            self.
                            tr('There are data sets that are dependent on this field, '
                               'it cant be removed.'))
                        stop_removing = True
                if stop_removing:
                    continue
                sql = "delete from fields where field_name='{f}'".format(
                    f=field_name)
                self.db.execute_sql(sql)
                self.parent.dock_widget.LWFields.takeItem(j)
                j -= 1

    def view_fields(self):
        """Add all fields that aren't displayed on the canvas,
        if no background map is loaded Google maps are loaded."""
        defined_field = self.defined_field
        if defined_field == '':
            add_background()
        sources = [
            layer.name().split('_')[0]
            for layer in QgsProject.instance().mapLayers().values()
        ]
        fields_db = self.db.execute_and_return("select field_name from fields")
        task = QgsTask.fromFunction('Adding fields to the canvas',
                                    add_fields_2_canvas,
                                    self.db,
                                    fields_db,
                                    defined_field,
                                    sources,
                                    on_finished=self.finish)
        self.tsk_mngr.addTask(task)

    def finish(self, result, values):
        """Produces either an error message telling what went wrong or adds the fields to canvas and zoom to the layers.

        Parameters
        ----------
        result: object
        values: list
            If all went ok:
                [True, list of layers]
            Else:
                [False, exception, traceback]
        """
        if values[0] is False:
            QMessageBox.information(
                None, self.tr('Error'),
                self.tr(
                    'Following error occurred: {m}\n\n Traceback: {t}'.format(
                        m=values[1], t=values[2])))
            return
        for layer in values[-1]:
            QgsProject.instance().addMapLayer(layer)
        if self.defined_field == '':
            set_zoom(self.parent.iface, 1.1)
        self.defined_field = ''

    def quit(self):
        """Closes the widget."""
        self.AFD.PBSelectExtent.clicked.disconnect()
        self.AFD.PBSave.clicked.disconnect()
        self.AFD.PBHelp.clicked.disconnect()
        self.AFD.PBQuit.clicked.disconnect()
        self.AFD.done(0)

    def save(self):
        """Saves the field in the database"""
        try:
            self.iface.actionSaveActiveLayerEdits().trigger()
            self.iface.actionToggleEditing().trigger()
            feature = self.field.getFeature(1)
            QgsProject.instance().removeMapLayers([self.field.id()])
        except:
            QMessageBox.information(
                None, self.tr("Error:"),
                self.
                tr('No coordinates where found, did you mark the field on the canvas?'
                   ))
            return
        polygon = feature.geometry().asWkt()
        name = self.AFD.LEFieldName.text()
        if len(name) == 0:
            QMessageBox.information(None, self.tr('Error:'),
                                    self.tr('Field name must be filled in.'))
            return
        sql = """Insert into fields (field_name, polygon) 
        VALUES ('{name}', st_geomfromtext('{poly}', 4326))""".format(
            name=name, poly=polygon)
        try:
            self.db.execute_sql(sql)
        except IntegrityError:
            QMessageBox.information(
                None, self.tr('Error:'),
                self.tr(
                    'Field name all ready exist, please select a new name'))
            return
        except InternalError as e:
            QMessageBox.information(None, self.tr('Error:'), str(e))
            return
        _name = QApplication.translate("qadashboard", name, None)
        item = QListWidgetItem(_name, self.dock_widget.LWFields)
        item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
        item.setCheckState(QtCore.Qt.Unchecked)
        self.defined_field = name
        self.view_fields()

    def help(self):
        """A function that gives some advice on how the function works for the user.
        """
        QMessageBox.information(
            None, self.tr("Help:"),
            self.
            tr('Here is where you add a field.\n'
               '1. Start with giving the field a name.\n'
               '2. Press "select extent" and switch to the QGIS window and zoom to your field.\n'
               '3. To mark your field, left click with the mouse in one corner of the field.\n'
               'then left click in all corners of the field then right click anywhere on the map.\n'
               '(There might be some errors while clicking the corners if the lines are crossing each other but in the end this does not matter if they does not do it in the end)\n'
               '4. Press "Save field" to store the field.\n'
               '5. When all fields are added press "Finished"'))
        return
    def testWriteWithBinaryField(self):
        """
        Test writing with a binary field
        :return:
        """
        basetestpath = tempfile.mkdtemp()

        tmpfile = os.path.join(basetestpath, 'binaryfield.sqlite')
        ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
        lyr = ds.CreateLayer('test',
                             geom_type=ogr.wkbPoint,
                             options=['FID=fid'])
        lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString))
        lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger))
        lyr.CreateField(ogr.FieldDefn('binfield', ogr.OFTBinary))
        lyr.CreateField(ogr.FieldDefn('binfield2', ogr.OFTBinary))
        f = None
        ds = None

        vl = QgsVectorLayer(tmpfile)
        self.assertTrue(vl.isValid())

        # check that 1 of its fields is a bool
        fields = vl.fields()
        self.assertEqual(
            fields.at(fields.indexFromName('binfield')).type(),
            QVariant.ByteArray)

        dp = vl.dataProvider()
        f = QgsFeature(fields)
        bin_1 = b'xxx'
        bin_2 = b'yyy'
        bin_val1 = QByteArray(bin_1)
        bin_val2 = QByteArray(bin_2)
        f.setAttributes([1, 'str', 100, bin_val1, bin_val2])
        self.assertTrue(dp.addFeature(f))

        # write a gpkg package with a binary field
        filename = os.path.join(str(QDir.tempPath()), 'with_bin_field')
        rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(
            vl, filename, 'utf-8', vl.crs(), 'GPKG')

        self.assertEqual(rc, QgsVectorFileWriter.NoError)

        # open the resulting geopackage
        vl = QgsVectorLayer(filename + '.gpkg', '', 'ogr')
        self.assertTrue(vl.isValid())
        fields = vl.fields()

        # test type of converted field
        idx = fields.indexFromName('binfield')
        self.assertEqual(fields.at(idx).type(), QVariant.ByteArray)
        idx2 = fields.indexFromName('binfield2')
        self.assertEqual(fields.at(idx2).type(), QVariant.ByteArray)

        # test values
        self.assertEqual(vl.getFeature(1).attributes()[idx], bin_val1)
        self.assertEqual(vl.getFeature(1).attributes()[idx2], bin_val2)

        del vl
        os.unlink(filename + '.gpkg')
class TestStratigraphy(utils_for_tests.MidvattenTestSpatialiteDbSv):
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.
                mock_instance_settings_database)
    def create_and_select_vlayer(self):
        self.qgs = QgsApplication([], True)
        self.qgs.initQgis()

        self.midvatten.ms.settingsdict['secplotdrillstop'] = "%berg%"

        dbconnection = db_utils.DbConnectionManager()
        uri = dbconnection.uri
        uri.setDataSource('', 'obs_points', 'geometry', '', 'rowid')
        dbtype = db_utils.get_dbtype(dbconnection.dbtype)
        self.vlayer = QgsVectorLayer(uri.uri(), 'TestLayer', dbtype)
        features = self.vlayer.getFeatures()
        feature_ids = [feature.id() for feature in features]
        self.vlayer.selectByIds(feature_ids)
        print("1. Valid vlayer '{}'".format(self.vlayer.isValid()))
        print("2. feature_ids: " + str(feature_ids))
        print("3. QgsVectorLayer.selectedFeatureIds: " +
              str(self.vlayer.selectedFeatureIds()))
        print("4. QgsVectorLayer.getSelectedFeatures: " +
              str([x.id() for x in self.vlayer.getSelectedFeatures()]))
        print("5. QgsVectorLayer.getFeature(): " +
              str([self.vlayer.getFeature(x).id() for x in feature_ids]))
        print("6. QgsVectorLayer.getFeature() type: " +
              str([str(type(self.vlayer.getFeature(x))) for x in feature_ids]))
        print("7. QgsVectorLayer.getFeatures(): " +
              str([x.id() for x in self.vlayer.getFeatures(feature_ids)]))

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.
                mock_instance_settings_database)
    def test_stratigraphy(self, mock_skippopup, mock_messagebar):
        """
        
        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        db_utils.sql_alter_db(
            '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('1', 5, ST_GeomFromText('POINT(633466 711659)', 3006))'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('2', 10, ST_GeomFromText('POINT(6720727 016568)', 3006))'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('3', 20, ST_GeomFromText('POINT(6720728 016569)', 3006))'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 1, 0, 1, 'sand', 'sand', '3', 'j')'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 2, 1, 4.5, 'morän', 'morän', '3', 'j')'''
        )
        self.create_and_select_vlayer()

        dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict)

        dlg.showSurvey()
        print(str(mock_skippopup.mock_calls))
        test = utils.anything_to_string_representation(dlg.data)
        test_survey = utils.anything_to_string_representation(
            repr(dlg.data['1']))
        test_strata = utils.anything_to_string_representation(
            utils.returnunicode(dlg.data['1'].strata, keep_containers=True))

        assert len(mock_skippopup.mock_calls) == 0
        assert len(mock_messagebar.mock_calls) == 0
        assert test == """{"1": SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')}"""
        assert test_survey == '''"SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"'''
        print("Test strata " + test_strata)
        assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '3', 'morän', 'moran', 1.000000-4.500000)"]'''

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.
                mock_instance_settings_database)
    def test_stratigraphy_with_other_obsid_numbers(self, mock_skippopup,
                                                   mock_messagebar):
        """

        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        db_utils.sql_alter_db(
            '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('8', 5, ST_GeomFromText('POINT(633466 711659)', 3006))'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('9', 10, ST_GeomFromText('POINT(6720727 016568)', 3006))'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('10', 20, ST_GeomFromText('POINT(6720728 016569)', 3006))'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('8', 1, 0, 1, 'sand', 'sand', '3', 'j')'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('8', 2, 1, 4.5, 'morän', 'morän', '3', 'j')'''
        )
        self.create_and_select_vlayer()

        dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict)

        dlg.showSurvey()
        print(str(mock_skippopup.mock_calls))
        test = utils.anything_to_string_representation(dlg.data)
        test_survey = utils.anything_to_string_representation(
            repr(dlg.data['8']))
        test_strata = utils.anything_to_string_representation(
            utils.returnunicode(dlg.data['8'].strata, keep_containers=True))

        assert len(mock_skippopup.mock_calls) == 0
        assert len(mock_messagebar.mock_calls) == 0
        assert test == """{"8": SURVEY('8', 5.000000, '<QgsPointXY: POINT(633466 711659)>')}"""
        assert test_survey == '''"SURVEY('8', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"'''
        print("Test strata " + test_strata)
        assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '3', 'morän', 'moran', 1.000000-4.500000)"]'''

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.
                mock_instance_settings_database)
    def test_stratigraphy_with_string_obsid(self, mock_skippopup,
                                            mock_messagebar):
        """

        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        db_utils.sql_alter_db(
            '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('P1', 5, ST_GeomFromText('POINT(633466 711659)', 3006))'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('P2', 10, ST_GeomFromText('POINT(6720727 016568)', 3006))'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('P3', 20, ST_GeomFromText('POINT(6720728 016569)', 3006))'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('P1', 1, 0, 1, 'sand', 'sand', '3', 'j')'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('P1', 2, 1, 4.5, 'morän', 'morän', '3', 'j')'''
        )
        self.create_and_select_vlayer()

        dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict)

        dlg.showSurvey()
        print(str(mock_skippopup.mock_calls))
        test = utils.anything_to_string_representation(dlg.data)
        test_survey = utils.anything_to_string_representation(
            repr(dlg.data['P1']))
        test_strata = utils.anything_to_string_representation(
            utils.returnunicode(dlg.data['P1'].strata, keep_containers=True))

        assert len(mock_skippopup.mock_calls) == 0
        assert len(mock_messagebar.mock_calls) == 0
        assert test == """{"P1": SURVEY('P1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')}"""
        assert test_survey == '''"SURVEY('P1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"'''
        print("Test strata " + test_strata)
        assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '3', 'morän', 'moran', 1.000000-4.500000)"]'''

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.
                mock_instance_settings_database)
    def test_stratigraphy_gap(self, mock_skippopup, mock_messagebar):
        """
        
        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        db_utils.sql_alter_db(
            '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('1', 5, ST_GeomFromText('POINT(633466 711659)', 3006))'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('2', 10, ST_GeomFromText('POINT(6720727 016568)', 3006))'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('3', 20, ST_GeomFromText('POINT(6720728 016569)', 3006))'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 1, 0, 1, 'sand', 'sand', '3', 'j')'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 2, 2, 4.5, 'morän', 'morän', '3', 'j')'''
        )

        self.create_and_select_vlayer()

        dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict)

        dlg.showSurvey()
        test = utils.anything_to_string_representation(dlg.data)
        test_survey = utils.anything_to_string_representation(
            repr(dlg.data['1']))
        test_strata = utils.anything_to_string_representation(
            utils.returnunicode(dlg.data['1'].strata, keep_containers=True))

        assert len(mock_skippopup.mock_calls) == 0
        assert len(mock_messagebar.mock_calls) == 0
        assert test == """{"1": SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')}"""
        assert test_survey == '''"SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"'''
        print("Test strata " + test_strata)
        assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '', '', '', 1.000000-2.000000)", "strata(3, '3', 'morän', 'moran', 2.000000-4.500000)"]'''

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.
                mock_instance_settings_database)
    def test_stratigraphy_missing_h_gs_use_h_toc(self, mock_skippopup,
                                                 mock_messagebar):
        """
        
        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        db_utils.sql_alter_db(
            '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('1', 5, ST_GeomFromText('POINT(633466 711659)', 3006))'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO obs_points (obsid, h_gs, h_toc, geometry) VALUES ('2', NULL, 10, ST_GeomFromText('POINT(6720727 016568)', 3006))'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO obs_points (obsid, geometry) VALUES ('3', ST_GeomFromText('POINT(6720728 016569)', 3006))'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 1, 0, 1, 'sand', 'sand', '3', 'j')'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 2, 1, 4.5, 'morän', 'morän', '3', 'j')'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('2', 1, 0, 1, 'sand', 'sand', '3', 'j')'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('2', 2, 1, 4.5, 'morän', 'morän', '3', 'j')'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('3', 1, 0, 2, 'sand', 'sand', '3', 'j')'''
        )
        db_utils.sql_alter_db(
            '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('3', 2, 2, 6, 'morän', 'morän', '3', 'j')'''
        )
        self.create_and_select_vlayer()

        dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict)

        dlg.showSurvey()
        test = utils.anything_to_string_representation(dlg.data)
        test_survey = utils.anything_to_string_representation(
            repr(dlg.data['1']))
        test_strata = utils.anything_to_string_representation(
            utils.returnunicode(dlg.data['1'].strata, keep_containers=True))

        assert len(mock_skippopup.mock_calls) == 1
        print(str(mock_skippopup.mock_calls))
        print(str(mock_messagebar.mock_calls))
        assert mock_skippopup.mock_calls == [
            mock.call('Warning, h_gs is missing. See messagebar.')
        ]
        assert mock_messagebar.mock_calls == [
            mock.call.warning(
                bar_msg="Obsid 2: using h_gs '' failed, using 'h_toc' instead.",
                duration=90,
                log_msg='False'),
            mock.call.warning(
                bar_msg="Obsid 3: using h_gs '' failed, using '-1' instead.",
                duration=90,
                log_msg='False')
        ]
        print(test)

        assert test == """{"1": SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>'), "2": SURVEY('2', 10.000000, '<QgsPointXY: POINT(6720727 16568)>'), "3": SURVEY('3', -1.000000, '<QgsPointXY: POINT(6720728 16569)>')}"""
        print("test_survey " + test_survey)
        assert test_survey == '''"SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"'''
        print("Test strata " + test_strata)
        assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '3', 'morän', 'moran', 1.000000-4.500000)"]'''

    def tearDown(self):
        QgsProject.instance().addMapLayer(self.vlayer)
        QgsProject.instance().removeMapLayer(self.vlayer.id())
        super(self.__class__, self).tearDown()
        def _test(autoTransaction):
            """Test buffer methods within and without transactions

            - create a feature
            - save
            - retrieve the feature
            - change geom and attrs
            - test changes are seen in the buffer
            """
            def _check_feature(wkt):

                f = next(layer_a.getFeatures())
                self.assertEqual(f.geometry().asWkt().upper(), wkt)
                f = list(buffer.addedFeatures().values())[0]
                self.assertEqual(f.geometry().asWkt().upper(), wkt)

            ml = QgsVectorLayer(
                'Point?crs=epsg:4326&field=int:integer&field=int2:integer',
                'test', 'memory')
            self.assertTrue(ml.isValid())

            d = QTemporaryDir()
            options = QgsVectorFileWriter.SaveVectorOptions()
            options.driverName = 'GPKG'
            options.layerName = 'layer_a'
            err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3(
                ml, os.path.join(d.path(), 'transaction_test.gpkg'),
                QgsCoordinateTransformContext(), options)

            self.assertEqual(err, QgsVectorFileWriter.NoError)
            self.assertTrue(os.path.isfile(newFileName))

            layer_a = QgsVectorLayer(newFileName + '|layername=layer_a')

            self.assertTrue(layer_a.isValid())

            project = QgsProject()
            project.setAutoTransaction(autoTransaction)
            project.addMapLayers([layer_a])

            ###########################################
            # Tests with a new feature

            self.assertTrue(layer_a.startEditing())
            buffer = layer_a.editBuffer()

            f = QgsFeature(layer_a.fields())
            f.setAttribute('int', 123)
            f.setGeometry(QgsGeometry.fromWkt('point(7 45)'))
            self.assertTrue(layer_a.addFeatures([f]))

            _check_feature('POINT (7 45)')

            # Need to fetch the feature because its ID is NULL (-9223372036854775808)
            f = next(layer_a.getFeatures())

            self.assertEqual(len(buffer.addedFeatures()), 1)
            layer_a.undoStack().undo()
            self.assertEqual(len(buffer.addedFeatures()), 0)
            layer_a.undoStack().redo()
            self.assertEqual(len(buffer.addedFeatures()), 1)
            f = list(buffer.addedFeatures().values())[0]
            self.assertEqual(f.attribute('int'), 123)

            # Now change attribute
            self.assertEqual(buffer.changedAttributeValues(), {})
            spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged)
            layer_a.changeAttributeValue(f.id(), 1, 321)
            self.assertEqual(len(spy_attribute_changed), 1)
            self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321])

            self.assertEqual(len(buffer.addedFeatures()), 1)
            # This is surprising: because it was a new feature it has been changed directly
            self.assertEqual(buffer.changedAttributeValues(), {})
            f = list(buffer.addedFeatures().values())[0]
            self.assertEqual(f.attribute('int'), 321)

            spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged)
            layer_a.undoStack().undo()
            self.assertEqual(len(spy_attribute_changed), 1)
            self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 123])
            self.assertEqual(buffer.changedAttributeValues(), {})
            f = list(buffer.addedFeatures().values())[0]
            self.assertEqual(f.attribute('int'), 123)
            f = next(layer_a.getFeatures())
            self.assertEqual(f.attribute('int'), 123)

            # Change multiple attributes
            spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged)
            layer_a.changeAttributeValues(f.id(), {1: 321, 2: 456})
            self.assertEqual(len(spy_attribute_changed), 2)
            self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321])
            self.assertEqual(spy_attribute_changed[1], [f.id(), 2, 456])
            buffer = layer_a.editBuffer()
            # This is surprising: because it was a new feature it has been changed directly
            self.assertEqual(buffer.changedAttributeValues(), {})

            spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged)
            layer_a.undoStack().undo()
            # This is because QgsVectorLayerUndoCommandChangeAttribute plural
            if not autoTransaction:
                layer_a.undoStack().undo()
            f = next(layer_a.getFeatures())
            self.assertEqual(f.attribute('int'), 123)
            self.assertEqual(f.attribute('int2'), None)
            self.assertEqual(len(spy_attribute_changed), 2)
            self.assertEqual(
                spy_attribute_changed[1 if autoTransaction else 0],
                [f.id(), 2, None])
            self.assertEqual(
                spy_attribute_changed[0 if autoTransaction else 1],
                [f.id(), 1, 123])

            # Change geometry
            f = next(layer_a.getFeatures())
            spy_geometry_changed = QSignalSpy(layer_a.geometryChanged)
            self.assertTrue(
                layer_a.changeGeometry(f.id(),
                                       QgsGeometry.fromWkt('point(9 43)')))
            self.assertTrue(len(spy_geometry_changed), 1)
            self.assertEqual(spy_geometry_changed[0][0], f.id())
            self.assertEqual(spy_geometry_changed[0][1].asWkt(),
                             QgsGeometry.fromWkt('point(9 43)').asWkt())

            _check_feature('POINT (9 43)')
            self.assertEqual(buffer.changedGeometries(), {})

            layer_a.undoStack().undo()

            _check_feature('POINT (7 45)')
            self.assertEqual(buffer.changedGeometries(), {})

            self.assertTrue(
                layer_a.changeGeometry(f.id(),
                                       QgsGeometry.fromWkt('point(9 43)')))
            _check_feature('POINT (9 43)')

            self.assertTrue(
                layer_a.changeGeometry(f.id(),
                                       QgsGeometry.fromWkt('point(10 44)')))
            _check_feature('POINT (10 44)')

            # This is another surprise: geometry edits get collapsed into a single
            # one because they have the same hardcoded id
            layer_a.undoStack().undo()
            _check_feature('POINT (7 45)')

            self.assertTrue(layer_a.commitChanges())

            ###########################################
            # Tests with the existing feature

            # Get the feature
            f = next(layer_a.getFeatures())
            self.assertTrue(f.isValid())
            self.assertEqual(f.attribute('int'), 123)
            self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)')

            # Change single attribute
            self.assertTrue(layer_a.startEditing())
            spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged)
            layer_a.changeAttributeValue(f.id(), 1, 321)
            self.assertEqual(len(spy_attribute_changed), 1)
            self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321])
            buffer = layer_a.editBuffer()
            self.assertEqual(buffer.changedAttributeValues(), {1: {1: 321}})

            f = next(layer_a.getFeatures())
            self.assertEqual(f.attribute(1), 321)

            spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged)
            layer_a.undoStack().undo()
            f = next(layer_a.getFeatures())
            self.assertEqual(f.attribute(1), 123)
            self.assertEqual(len(spy_attribute_changed), 1)
            self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 123])
            self.assertEqual(buffer.changedAttributeValues(), {})

            # Change attributes
            spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged)
            layer_a.changeAttributeValues(f.id(), {1: 111, 2: 654})
            self.assertEqual(len(spy_attribute_changed), 2)
            self.assertEqual(spy_attribute_changed[0], [1, 1, 111])
            self.assertEqual(spy_attribute_changed[1], [1, 2, 654])
            f = next(layer_a.getFeatures())
            self.assertEqual(f.attributes(), [1, 111, 654])
            self.assertEqual(buffer.changedAttributeValues(),
                             {1: {
                                 1: 111,
                                 2: 654
                             }})

            spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged)
            layer_a.undoStack().undo()
            # This is because QgsVectorLayerUndoCommandChangeAttribute plural
            if not autoTransaction:
                layer_a.undoStack().undo()
            self.assertEqual(len(spy_attribute_changed), 2)
            self.assertEqual(
                spy_attribute_changed[0 if autoTransaction else 1],
                [1, 1, 123])
            self.assertEqual(
                spy_attribute_changed[1 if autoTransaction else 0],
                [1, 2, None])
            f = next(layer_a.getFeatures())
            self.assertEqual(f.attributes(), [1, 123, None])
            self.assertEqual(buffer.changedAttributeValues(), {})

            # Change geometry
            spy_geometry_changed = QSignalSpy(layer_a.geometryChanged)
            self.assertTrue(
                layer_a.changeGeometry(f.id(),
                                       QgsGeometry.fromWkt('point(9 43)')))
            self.assertEqual(spy_geometry_changed[0][0], 1)
            self.assertEqual(spy_geometry_changed[0][1].asWkt(),
                             QgsGeometry.fromWkt('point(9 43)').asWkt())

            f = next(layer_a.getFeatures())
            self.assertEqual(f.geometry().asWkt().upper(), 'POINT (9 43)')
            self.assertEqual(buffer.changedGeometries()[1].asWkt().upper(),
                             'POINT (9 43)')

            spy_geometry_changed = QSignalSpy(layer_a.geometryChanged)
            layer_a.undoStack().undo()
            self.assertEqual(spy_geometry_changed[0][0], 1)
            self.assertEqual(spy_geometry_changed[0][1].asWkt(),
                             QgsGeometry.fromWkt('point(7 45)').asWkt())
            self.assertEqual(buffer.changedGeometries(), {})
            f = next(layer_a.getFeatures())

            self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)')
            self.assertEqual(buffer.changedGeometries(), {})

            # Delete an existing feature
            self.assertTrue(layer_a.deleteFeature(f.id()))
            with self.assertRaises(StopIteration):
                next(layer_a.getFeatures())
            self.assertEqual(buffer.deletedFeatureIds(), [f.id()])

            layer_a.undoStack().undo()
            self.assertTrue(layer_a.getFeature(f.id()).isValid())
            self.assertEqual(buffer.deletedFeatureIds(), [])

            ###########################################
            # Test delete

            # Delete a new feature
            f = QgsFeature(layer_a.fields())
            f.setAttribute('int', 555)
            f.setGeometry(QgsGeometry.fromWkt('point(8 46)'))
            self.assertTrue(layer_a.addFeatures([f]))
            f = [
                f for f in layer_a.getFeatures() if f.attribute('int') == 555
            ][0]
            self.assertTrue(f.id() in buffer.addedFeatures())
            self.assertTrue(layer_a.deleteFeature(f.id()))
            self.assertFalse(f.id() in buffer.addedFeatures())
            self.assertFalse(f.id() in buffer.deletedFeatureIds())

            layer_a.undoStack().undo()
            self.assertTrue(f.id() in buffer.addedFeatures())

            ###########################################
            # Add attribute

            field = QgsField('attr1', QVariant.String)
            self.assertTrue(layer_a.addAttribute(field))
            self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1)
            self.assertEqual(buffer.addedAttributes(), [field])

            layer_a.undoStack().undo()
            self.assertEqual(layer_a.fields().lookupField(field.name()), -1)
            self.assertEqual(buffer.addedAttributes(), [])

            layer_a.undoStack().redo()
            self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1)
            self.assertEqual(buffer.addedAttributes(), [field])

            self.assertTrue(layer_a.commitChanges())

            ###########################################
            # Remove attribute

            self.assertTrue(layer_a.startEditing())
            buffer = layer_a.editBuffer()

            attr_idx = layer_a.fields().lookupField(field.name())
            self.assertNotEqual(attr_idx, -1)

            self.assertTrue(layer_a.deleteAttribute(attr_idx))
            self.assertEqual(buffer.deletedAttributeIds(), [attr_idx])
            self.assertEqual(layer_a.fields().lookupField(field.name()), -1)

            layer_a.undoStack().undo()
            self.assertEqual(buffer.deletedAttributeIds(), [])
            self.assertEqual(layer_a.fields().lookupField(field.name()),
                             attr_idx)

            # This is totally broken at least on OGR/GPKG: the rollback
            # does not restore the original fields
            if False:

                layer_a.undoStack().redo()
                self.assertEqual(buffer.deletedAttributeIds(), [attr_idx])
                self.assertEqual(layer_a.fields().lookupField(field.name()),
                                 -1)

                # Rollback!
                self.assertTrue(layer_a.rollBack())

                self.assertIn('attr1', layer_a.dataProvider().fields().names())
                self.assertIn('attr1', layer_a.fields().names())
                self.assertEqual(layer_a.fields().names(),
                                 layer_a.dataProvider().fields().names())

                attr_idx = layer_a.fields().lookupField(field.name())
                self.assertNotEqual(attr_idx, -1)

                self.assertTrue(layer_a.startEditing())
                attr_idx = layer_a.fields().lookupField(field.name())
                self.assertNotEqual(attr_idx, -1)

            ###########################################
            # Rename attribute

            attr_idx = layer_a.fields().lookupField(field.name())
            self.assertEqual(layer_a.fields().lookupField('new_name'), -1)
            self.assertTrue(layer_a.renameAttribute(attr_idx, 'new_name'))
            self.assertEqual(layer_a.fields().lookupField('new_name'),
                             attr_idx)

            layer_a.undoStack().undo()
            self.assertEqual(layer_a.fields().lookupField(field.name()),
                             attr_idx)
            self.assertEqual(layer_a.fields().lookupField('new_name'), -1)

            layer_a.undoStack().redo()
            self.assertEqual(layer_a.fields().lookupField('new_name'),
                             attr_idx)
            self.assertEqual(layer_a.fields().lookupField(field.name()), -1)

            #############################################
            # Try hard to make this fail for transactions
            if autoTransaction:
                self.assertTrue(layer_a.commitChanges())
                self.assertTrue(layer_a.startEditing())
                f = next(layer_a.getFeatures())

                # Do
                for i in range(10):
                    spy_attribute_changed = QSignalSpy(
                        layer_a.attributeValueChanged)
                    layer_a.changeAttributeValue(f.id(), 2, i)
                    self.assertEqual(len(spy_attribute_changed), 1)
                    self.assertEqual(spy_attribute_changed[0], [f.id(), 2, i])
                    buffer = layer_a.editBuffer()
                    self.assertEqual(buffer.changedAttributeValues(),
                                     {f.id(): {
                                          2: i
                                      }})
                    f = next(layer_a.getFeatures())
                    self.assertEqual(f.attribute(2), i)

                # Undo/redo
                for i in range(9):

                    # Undo
                    spy_attribute_changed = QSignalSpy(
                        layer_a.attributeValueChanged)
                    layer_a.undoStack().undo()
                    f = next(layer_a.getFeatures())
                    self.assertEqual(f.attribute(2), 8 - i)
                    self.assertEqual(len(spy_attribute_changed), 1)
                    self.assertEqual(spy_attribute_changed[0],
                                     [f.id(), 2, 8 - i])
                    buffer = layer_a.editBuffer()
                    self.assertEqual(buffer.changedAttributeValues(),
                                     {f.id(): {
                                          2: 8 - i
                                      }})

                    # Redo
                    spy_attribute_changed = QSignalSpy(
                        layer_a.attributeValueChanged)
                    layer_a.undoStack().redo()
                    f = next(layer_a.getFeatures())
                    self.assertEqual(f.attribute(2), 9 - i)
                    self.assertEqual(len(spy_attribute_changed), 1)
                    self.assertEqual(spy_attribute_changed[0],
                                     [f.id(), 2, 9 - i])

                    # Undo again
                    spy_attribute_changed = QSignalSpy(
                        layer_a.attributeValueChanged)
                    layer_a.undoStack().undo()
                    f = next(layer_a.getFeatures())
                    self.assertEqual(f.attribute(2), 8 - i)
                    self.assertEqual(len(spy_attribute_changed), 1)
                    self.assertEqual(spy_attribute_changed[0],
                                     [f.id(), 2, 8 - i])
                    buffer = layer_a.editBuffer()
                    self.assertEqual(buffer.changedAttributeValues(),
                                     {f.id(): {
                                          2: 8 - i
                                      }})

                    # Last check
                    f = next(layer_a.getFeatures())
                    self.assertEqual(f.attribute(2), 8 - i)

                self.assertEqual(buffer.changedAttributeValues(),
                                 {f.id(): {
                                      2: 0
                                  }})
                layer_a.undoStack().undo()
                buffer = layer_a.editBuffer()
                self.assertEqual(buffer.changedAttributeValues(), {})
                f = next(layer_a.getFeatures())
                self.assertEqual(f.attribute(2), None)
Exemple #23
0
def layerSubsetSave(rasterLayer: QgsRasterLayer, domainLayer: QgsVectorLayer,
                    subsetName: str) -> None:
    """Description: Processes a raster image into a vector polygon ocean/land mask.
		Make sure to save the shapefile, as it will be deleted otherwise! 
		Input:  QgsRasterLayer rasterLayer - layer that contains the raster image to process
				QgsVectorLayer domainLayer - layer that contains a polygon specifying the bounds of the raster image to process
				string name - output file name.
		Output: QgsRasterLayer, QgsVectorLayer - objects referencing the new mask layers
	"""

    # Get basic file name information on geotiff, raster image, masked raster subset image, and masked vector subset shp file
    fileSource = rasterLayer.source()
    fileInfo = QFileInfo(fileSource)
    fileName = fileInfo.baseName()
    savePaths = getSavePaths(fileSource, domainLayer, 'tif')
    subsetPath = savePaths + '/' + subsetName + '.tif'

    # Load geotiff and get domain layer/bounding box of area to mask
    geotiff = gdal.Open(fileSource)
    feature = domainLayer.getFeature(0)
    domain = feature.geometry().boundingBox()
    prj = geotiff.GetProjection()
    srs = osr.SpatialReference(wkt=prj)
    if srs.GetAttrValue("PROJCS|AUTHORITY", 1) is not None:
        epsgCode = srs.GetAttrValue("PROJCS|AUTHORITY", 1)
    elif srs.GetAttrValue("AUTHORITY", 1) is not None:
        epsgCode = srs.GetAttrValue("AUTHORITY", 1)
    else:
        epsgCode = str(32621)
    rasterCRS = "EPSG:" + epsgCode

    crs = rasterLayer.crs()
    crs.createFromId(int(epsgCode))
    rasterLayer.setCrs(crs)
    rasterLayer.triggerRepaint()

    #rasterCRS = rasterLayer.crs().authid()
    domainCRS = domainLayer.crs().authid()
    bounds = geotiffWorldToPixelCoords(geotiff, domain, rasterCRS, domainCRS)

    band = geotiff.GetRasterBand(1)
    img_full = band.ReadAsArray(0, 0, geotiff.RasterXSize, geotiff.RasterYSize)
    img = img_full[int(round(bounds.yMinimum())):int(round(bounds.yMaximum())),
                   int(round(bounds.xMinimum())):int(round(bounds.xMaximum()))]
    print('bounds', bounds.yMinimum(), bounds.yMaximum(), bounds.xMinimum(),
          bounds.xMaximum())
    print('img.shape', img.shape, 'img_full.shape', img_full.shape)
    print("img min/max/mean:", img.min(), img.max(), np.mean(img, axis=(0, 1)))
    img = (img.astype(np.float32) / img.max() * 65535).astype(np.uint16)
    print("after img min/max/mean:", img.min(), img.max(),
          np.mean(img, axis=(0, 1)))

    # print('Save subset:', subsetPath, resolve('landsat_raw/' + domainLayer.name() + '/' + subsetName + '.png'))
    if not DRY_RUN:
        arrayToRaster(img, geotiff, bounds, subsetPath)
        imsave(
            resolve('landsat_raw/' + domainLayer.name() + '/' + subsetName +
                    '.png'), img)
        # imsave(resolve('small/' + domainLayer.name() + '/' + subsetName + '.png'), img)
        # imsave(os.path.join(r'D:\Daniel\Documents\Github\CALFIN Repo\reprocessing\images_1024', domainLayer.name(), subsetName + '.png'), img)
    try:
        #Gather BQA info
        fileSourceBQA = fileSource[:-7] + '_BQA.TIF'
        #Save BQA subset
        geotiffBQA = gdal.Open(fileSourceBQA)
        imgBQA = geotiffBQA.GetRasterBand(1)
        imgBQA = imgBQA.ReadAsArray(0, 0, geotiffBQA.RasterXSize,
                                    geotiffBQA.RasterYSize).astype(np.uint16)
        imgBQA = imgBQA[
            int(round(bounds.yMinimum())):int(round(bounds.yMaximum())),
            int(round(bounds.xMinimum())):int(round(bounds.xMaximum()))]
        # print('Save BQA subset:', subsetPathBQA, resolve('landsat_raw/' + domainLayer.name() + '/' + subsetName + '_bqa.png'))
        if not DRY_RUN:
            # arrayToRaster(imgBQA, geotiffBQA, bounds, subsetPathBQA)
            # print(fileSourceBQA, geotiffBQA.RasterXSize, geotiffBQA.RasterYSize)
            # print(int(round(bounds.yMinimum())), int(round(bounds.yMaximum())), int(round(bounds.xMinimum())), int(round(bounds.xMaximum())))
            # imsave(resolve('landsat_raw/' + domainLayer.name() + '/' + subsetName + '_bqa.png'), imgBQA)
            pass

        #Gather MTL info
        fileSourceMTL = fileSource[:-7] + '_MTL.txt'
        #Save MTL subset
        if not DRY_RUN:
            image_feats = [''] * 6
            with open(fileSourceMTL, 'r') as image_feats_source_file:
                lines = image_feats_source_file.readlines()
                for line in lines:
                    if 'SUN_AZIMUTH =' in line:
                        image_feats[0] = line.strip()
                    elif 'SUN_ELEVATION =' in line:
                        image_feats[1] = line.strip()
                    elif 'CLOUD_COVER ' in line:
                        image_feats[2] = line.strip()
                    elif 'CLOUD_COVER_LAND ' in line:
                        image_feats[3] = line.strip()
                    elif 'DATE_ACQUIRED =' in line:
                        image_feats[4] = line.strip()
                    elif 'GRID_CELL_SIZE_REFLECTIVE =' in line:
                        image_feats[5] = line.strip()
            savePath = resolve('landsat_raw/' + domainLayer.name() + '/' +
                               subsetName + '_mtl.txt')
            with open(savePath, 'w') as image_feats_dest_file:
                for line in image_feats:
                    image_feats_dest_file.write(str(line) + '\n')
    except:
        print('No BQA/MTL found for:', subsetName)

    return img.shape
Exemple #24
0
def domainInRaster(rasterLayer: QgsRasterLayer,
                   domainLayer: QgsVectorLayer) -> bool:
    """Returns bool if domain is within bounds of geotiff in rasterLayer
	:param rasterLayer: QgsRasterLayer
	:param domainLayer: QgsVectorLayer
	"""
    # Get basic file name information on geotiff, raster image, masked raster subset image, and masked vector subset shp file
    fileSource = rasterLayer.source()

    # Load geotiff and get domain layer/bounding box of area to mask
    geotiff = gdal.Open(fileSource)
    feature = domainLayer.getFeature(0)
    domain = feature.geometry().boundingBox()
    prj = geotiff.GetProjection()
    srs = osr.SpatialReference(wkt=prj)
    if srs.GetAttrValue("PROJCS|AUTHORITY", 1) is not None:
        epsgCode = srs.GetAttrValue("PROJCS|AUTHORITY", 1)
    elif srs.GetAttrValue("AUTHORITY", 1) is not None:
        epsgCode = srs.GetAttrValue("AUTHORITY", 1)
    else:
        epsgCode = str(32621)
    rasterCRS = "EPSG:" + epsgCode

    crs = rasterLayer.crs()
    crs.createFromId(int(epsgCode))

    domainCRS = domainLayer.crs().authid()
    bounds = geotiffWorldToPixelCoords(geotiff, domain, rasterCRS, domainCRS)

    #Gather BQA info
    fileSourceBQA = fileSource[:-7] + '_BQA.TIF'
    #Save BQA subset
    geotiffBQA = gdal.Open(fileSourceBQA)

    minX = int(round(bounds.yMinimum()))
    maxX = int(round(bounds.yMaximum()))
    minY = int(round(bounds.xMinimum()))
    maxY = int(round(bounds.xMaximum()))

    if minX < 0 or maxX > geotiff.RasterXSize or maxX > geotiffBQA.RasterXSize or minY < 0 or maxY > geotiff.RasterYSize or maxY > geotiffBQA.RasterYSize:
        return False
    else:
        #Check image is above Nodata percentage threshold
        band = geotiff.GetRasterBand(1)
        # Get raster statistics
        stats = band.GetStatistics(True, True)
        min_value, max_value = stats[0], stats[1]

        img_full = band.ReadAsArray(0, 0, geotiff.RasterXSize,
                                    geotiff.RasterYSize)
        img = img_full[
            int(round(bounds.yMinimum())):int(round(bounds.yMaximum())),
            int(round(bounds.xMinimum())):int(round(bounds.xMaximum()))]
        if img.shape[0] == 0 or img.shape[1] == 0:
            geotiff = None
            geotiffBQA = None
            print('Skipping: not in domain')
            return False
        noDataValue = 0.0
        #		print(min_value, max_value, img.shape)
        noDataValueThreshold = noDataValue + (max_value - min_value) * 0.006
        noDataCount = np.sum(img < noDataValue + noDataValueThreshold)
        percentNoData = noDataCount / img.size
        #		print('percentNoData', percentNoData, 'noDataCount', noDataCount, 'noDataValueThreshold', noDataValueThreshold)
        if percentNoData > nodata_threshold:
            geotiff = None
            geotiffBQA = None
            print('Skipping: Nodata percentage above threshold:',
                  percentNoData, ' > ', nodata_threshold)
            return False

        #Check image is above cloud percentage threshold
        bandBQA = geotiffBQA.GetRasterBand(1)
        imgBQA = bandBQA.ReadAsArray(minX, minY, maxX - minX,
                                     maxY - minY).astype(np.uint16)
        print('warning: check cloud mask parameters for MSS! (year < 1985)')
        masked = imgBQA & maskClouds
        cloudCount = np.sum(masked)
        percentCloud = cloudCount / 8.0 / imgBQA.size
        if percentCloud > cloud_threshold:
            geotiff = None
            geotiffBQA = None
            print('Skipping: Cloud percentage above threshold:', percentCloud,
                  ' > ', cloud_threshold)
            return False
    geotiff = None
    geotiffBQA = None
    return True
Exemple #25
0
    def testObjectIdDifferentName(self):
        """ Test that object id fields not named OBJECTID work correctly """

        endpoint = self.basetestpath + '/oid_fake_qgis_http_endpoint'
        with open(sanitize(endpoint, '?f=json'), 'wb') as f:
            f.write("""
        {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description":
        "QGIS Provider Test Layer.\n","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[],
        "minScale":72225,"maxScale":0,
        "defaultVisibility":true,
        "extent":{"xmin":-71.123,"ymin":66.33,"xmax":-65.32,"ymax":78.3,
        "spatialReference":{"wkid":4326,"latestWkid":4326}},
        "hasAttachments":false,"htmlPopupType":"esriServerHTMLPopupTypeAsHTMLText",
        "displayField":"LABEL","typeIdField":null,
        "fields":[{"name":"OBJECTID1","type":"esriFieldTypeOID","alias":"OBJECTID","domain":null},
        {"name":"pk","type":"esriFieldTypeInteger","alias":"pk","domain":null},
        {"name":"cnt","type":"esriFieldTypeInteger","alias":"cnt","domain":null}],
        "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false,
        "capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true,
        "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF",
        "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}"""
                    .encode('UTF-8'))

        with open(
                sanitize(
                    endpoint,
                    '/query?f=json_where=OBJECTID1=OBJECTID1_returnIdsOnly=true'
                ), 'wb') as f:
            f.write("""
        {
         "objectIdFieldName": "OBJECTID1",
         "objectIds": [
          5,
          3,
          1,
          2,
          4
         ]
        }
        """.encode('UTF-8'))

        with open(
                sanitize(
                    endpoint,
                    '/query?f=json&objectIds=5,3,1,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=OBJECTID1,pk,cnt&returnM=false&returnZ=false'
                ), 'wb') as f:
            f.write("""
        {
         "displayFieldName": "LABEL",
         "geometryType": "esriGeometryPoint",
         "spatialReference": {
          "wkid": 4326,
          "latestWkid": 4326
         },
         "fields":[{"name":"OBJECTID1","type":"esriFieldTypeOID","alias":"OBJECTID1","domain":null},
          {"name":"pk","type":"esriFieldTypeInteger","alias":"pk","domain":null},
          {"name":"cnt","type":"esriFieldTypeInteger","alias":"cnt","domain":null},
          {"name":"Shape","type":"esriFieldTypeGeometry","alias":"Shape","domain":null}],
         "features": [
          {
           "attributes": {
            "OBJECTID1": 5,
            "pk": 5,
            "cnt": -200,
            "name": null
           },
           "geometry": {
            "x": -71.123,
            "y": 78.23
           }
          }
         ]
        }""".encode('UTF-8'))

        # Create test layer
        vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'",
                            'test', 'arcgisfeatureserver')
        assert vl.isValid()

        f = vl.getFeature(0)
        assert f.isValid()
Exemple #26
0
    def processAlgorithm(self, parameters, context, feedback):
        feedback.pushInfo(self.tr("[QNEAT3Algorithm] This is a QNEAT3 Algorithm: '{}'".format(self.displayName())))
        network = self.parameterAsVectorLayer(parameters, self.INPUT, context) #QgsVectorLayer
        startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) #QgsPointXY
        max_dist = self.parameterAsDouble(parameters, self.MAX_DIST, context)#float
        cell_size = self.parameterAsInt(parameters, self.CELL_SIZE, context)#int
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) #int
        interpolation_method = self.parameterAsEnum(parameters, self.METHOD, context)#int

        entry_cost_calc_method = self.parameterAsEnum(parameters, self.ENTRY_COST_CALCULATION_METHOD, context) #int
        directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) #str (empty if no field given)
        forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) #str
        backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) #str
        bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) #str
        defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) #int
        speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) #str
        defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) #float
        tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) #float
        output_path = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)

        analysisCrs = network.sourceCrs()
        input_coordinates = [startPoint]
        input_point = getFeatureFromPointParameter(startPoint)
        
        feedback.pushInfo("[QNEAT3Algorithm] Building Graph...")
        feedback.setProgress(10)  
        net = Qneat3Network(network, input_coordinates, strategy, directionFieldName, forwardValue, backwardValue, bothValue, defaultDirection, analysisCrs, speedFieldName, defaultSpeed, tolerance, feedback)
        feedback.setProgress(40)
        
        analysis_point = Qneat3AnalysisPoint("point", input_point, "point_id", net, net.list_tiedPoints[0], entry_cost_calc_method, feedback)
        
        feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Pointcloud...")
        iso_pointcloud = net.calcIsoPoints([analysis_point], max_dist)
        feedback.setProgress(70)
        
        uri = "Point?crs={}&field=vertex_id:int(254)&field=cost:double(254,7)&field=origin_point_id:string(254)&index=yes".format(analysisCrs.authid())
        
        iso_pointcloud_layer = QgsVectorLayer(uri, "iso_pointcloud_layer", "memory")
        iso_pointcloud_provider = iso_pointcloud_layer.dataProvider()
        iso_pointcloud_provider.addFeatures(iso_pointcloud, QgsFeatureSink.FastInsert)
        
        feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Interpolation-Raster using QGIS TIN-Interpolator...")
        if interpolation_method == 0:
            feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Interpolation-Raster using QGIS TIN-Interpolator...")
            net.calcIsoTinInterpolation(iso_pointcloud_layer, cell_size, output_path)
            feedback.setProgress(99)
        else:


            #prepare numpy coordinate grids
            NoData_value = -9999
            raster_rectangle = iso_pointcloud_layer.extent()
            
            #implement spatial index for lines (closest line, etc...)
            spt_idx = QgsSpatialIndex(iso_pointcloud_layer.getFeatures(QgsFeatureRequest()), feedback)
            
            #top left point
            xmin = raster_rectangle.xMinimum()
            ymin = raster_rectangle.yMinimum()
            xmax = raster_rectangle.xMaximum()
            ymax = raster_rectangle.yMaximum()
            
            cols = int((xmax - xmin) / cell_size)
            rows = int((ymax - ymin) / cell_size)
            
            output_interpolation_raster = gdal.GetDriverByName('GTiff').Create(output_path, cols, rows, 1, gdal.GDT_Float64 )
            output_interpolation_raster.SetGeoTransform((xmin, cell_size, 0, ymax, 0, -cell_size))
            
            band = output_interpolation_raster.GetRasterBand(1)
            band.SetNoDataValue(NoData_value)
            
            #initialize zero array with 2 dimensions (according to rows and cols)
            raster_routingcost_data = zeros(shape=(rows, cols))
            
            #compute raster cell MIDpoints
            x_pos = linspace(xmin+(cell_size/2), xmax -(cell_size/2), raster_routingcost_data.shape[1])
            y_pos = linspace(ymax-(cell_size/2), ymin + (cell_size/2), raster_routingcost_data.shape[0])
            x_grid, y_grid = meshgrid(x_pos, y_pos) 
            
            feedback.pushInfo('[QNEAT3Network][calcQneatInterpolation] Beginning with interpolation')
            total_work = rows * cols
            counter = 0
    
            feedback.pushInfo('[QNEAT3Network][calcQneatInterpolation] Total workload: {} cells'.format(total_work))
            feedback.setProgress(0)
            for i in range(rows):
                for j in range(cols):
                    current_pixel_midpoint = QgsPointXY(x_grid[i,j],y_grid[i,j])
    
                    nearest_vertex_fid = spt_idx.nearestNeighbor(current_pixel_midpoint, 1)[0]
    
                    nearest_feature = iso_pointcloud_layer.getFeature(nearest_vertex_fid)
    
                    nearest_vertex = net.network.vertex(nearest_feature['vertex_id'])
    
                    #yields a list of all incoming and outgoing edges    
                    edges = nearest_vertex.incomingEdges() + nearest_vertex.outgoingEdges() 
                    
                    vertex_found = False
                    nearest_counter = 2
                    while vertex_found == False:
                        #find the second nearest vertex (eg, the vertex with least cost of all edges incoming to the first nearest vertex)
                        second_nearest_feature_fid = spt_idx.nearestNeighbor(current_pixel_midpoint, nearest_counter)[nearest_counter-1] 
                        second_nearest_feature = iso_pointcloud_layer.getFeature(second_nearest_feature_fid)
                        second_nearest_vertex_id = second_nearest_feature['vertex_id']
    
                        for edge_id in edges:
                            from_vertex_id = net.network.edge(edge_id).fromVertex()
                            to_vertex_id = net.network.edge(edge_id).toVertex()
    
                            if second_nearest_vertex_id == from_vertex_id: 
                                vertex_found = True
                                vertex_type = "from_vertex"
                                from_point = second_nearest_feature.geometry().asPoint()
                                from_vertex_cost = second_nearest_feature['cost']
                                
                            if second_nearest_vertex_id == to_vertex_id:
                                vertex_found = True
                                vertex_type = "to_vertex"
                                to_point = second_nearest_feature.geometry().asPoint()
                                to_vertex_cost = second_nearest_feature['cost']
                                
    
                        nearest_counter = nearest_counter + 1
                        """
                        if nearest_counter == 5:
                            vertex_found = True
                            vertex_type = "end_vertex"
                        """
    
                    if vertex_type == "from_vertex":
                        nearest_edge_geometry = QgsGeometry().fromPolylineXY([from_point, nearest_vertex.point()])
                        res = nearest_edge_geometry.closestSegmentWithContext(current_pixel_midpoint)
                        segment_point = res[1] #[0: distance, 1: point, 2: left_of, 3: epsilon for snapping]
                        dist_to_segment = segment_point.distance(current_pixel_midpoint)
                        dist_edge = from_point.distance(segment_point)
                        #feedback.pushInfo("dist_to_segment = {}".format(dist_to_segment))
                        #feedback.pushInfo("dist_on_edge = {}".format(dist_edge))
                        #feedback.pushInfo("cost = {}".format(from_vertex_cost))
                        pixel_cost = from_vertex_cost + dist_edge + dist_to_segment
                        raster_routingcost_data[i,j] = pixel_cost
                    elif vertex_type == "to_vertex":
                        nearest_edge_geometry = QgsGeometry().fromPolylineXY([nearest_vertex.point(), to_point])
                        res = nearest_edge_geometry.closestSegmentWithContext(current_pixel_midpoint)
                        segment_point = res[1] #[0: distance, 1: point, 2: left_of, 3: epsilon for snapping]
                        dist_to_segment = segment_point.distance(current_pixel_midpoint)
                        dist_edge = to_point.distance(segment_point)
                        #feedback.pushInfo("dist_to_segment = {}".format(dist_to_segment))
                        #feedback.pushInfo("dist_on_edge = {}".format(dist_edge))
                        #feedback.pushInfo("cost = {}".format(from_vertex_cost))
                        pixel_cost = to_vertex_cost + dist_edge + dist_to_segment
                        raster_routingcost_data[i,j] = pixel_cost
                    else:
                        pixel_cost = -99999#nearest_feature['cost'] + (nearest_vertex.point().distance(current_pixel_midpoint))
    
    
                    """
                    nearest_feature_pointxy = nearest_feature.geometry().asPoint()
                    nearest_feature_cost = nearest_feature['cost']
                    
                    dist_to_vertex = current_pixel_midpoint.distance(nearest_feature_pointxy)
                    #implement time cost
                    pixel_cost = dist_to_vertex + nearest_feature_cost
                    
                    raster_data[i,j] = pixel_cost
                    """
                    counter = counter+1
                    if counter%1000 == 0:
                        feedback.pushInfo("[QNEAT3Network][calcQneatInterpolation] Interpolated {} cells...".format(counter))
                    feedback.setProgress((counter/total_work)*100)
    
    
            band.WriteArray(raster_routingcost_data)
            outRasterSRS = osr.SpatialReference()
            outRasterSRS.ImportFromWkt(net.AnalysisCrs.toWkt())
            output_interpolation_raster.SetProjection(outRasterSRS.ExportToWkt())
            band.FlushCache()

        
        feedback.pushInfo("[QNEAT3Algorithm] Ending Algorithm")
        feedback.setProgress(100)           
        
        results = {}
        results[self.OUTPUT] = output_path
        return results
class TestVectorlayer(utils_for_tests.MidvattenTestSpatialiteDbSv):
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.mock_instance_settings_database)
    def create_vlayer(self, no_print=False):
        self.qgs = QgsApplication([], True)
        self.qgs.initQgis()

        dbconnection = db_utils.DbConnectionManager()
        uri = dbconnection.uri
        uri.setDataSource('', 'obs_points', 'geometry', '', 'obsid')
        dbtype = db_utils.get_dbtype(dbconnection.dbtype)
        self.vlayer = QgsVectorLayer(uri.uri(), 'TestLayer', dbtype)

        features = self.vlayer.getFeatures()
        feature_ids = [feature.id() for feature in features]

        if not no_print:
            print("1. Valid vlayer '{}'".format(self.vlayer.isValid()))
            print("2. feature_ids: " + str(feature_ids))
            print("5. QgsVectorLayer.getFeature(): " + str([self.vlayer.getFeature(x).id() for x in feature_ids]))
            print("6. QgsVectorLayer.getFeature() type: " + str([str(type(self.vlayer.getFeature(x))) for x in feature_ids]))
            print("7. QgsVectorLayer.getFeatures(): " + str([x.id() for x in self.vlayer.getFeatures(feature_ids)]))
            print("8. QgsVectorLayer.featureCount(): " + str(self.vlayer.featureCount()))

    def select_features(self, feature_ids=None, no_print=True):
        if feature_ids is None:
            features = self.vlayer.getFeatures()
            feature_ids = [feature.id() for feature in features]
        self.vlayer.selectByIds(feature_ids)

        if not no_print:
            print("3. QgsVectorLayer.selectedFeatureIds: " + str(self.vlayer.selectedFeatureIds()))
            print("4. QgsVectorLayer.getSelectedFeatures: " + str([x.id() for x in self.vlayer.getSelectedFeatures()]))

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.mock_instance_settings_database)
    def test_vlayer(self, mock_skippopup, mock_messagebar):
        """

        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        for obsid in [1, 2, 3]:
            db_utils.sql_alter_db('''INSERT INTO obs_points (obsid) VALUES ({})'''.format(str(obsid)))

        self.create_vlayer()
        self.select_features()
        feature_ids = [feature.id() for feature in self.vlayer.getFeatures()]

        reference_ids = (1, 2, 3)
        assert self.vlayer.isValid()
        assert len(feature_ids) == len(reference_ids)
        assert tuple(feature_ids) == reference_ids
        assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()])) == reference_ids
        assert tuple(sorted([x.id() for x in self.vlayer.getSelectedFeatures()])) == reference_ids
        assert tuple(sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)])) == reference_ids
        assert self.vlayer.featureCount() == 3

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.mock_instance_settings_database)
    def test_vlayer_other_ints_ids(self, mock_skippopup, mock_messagebar):
        """

        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        for obsid in [4, 5, 6]:
            db_utils.sql_alter_db('''INSERT INTO obs_points (obsid) VALUES ({})'''.format(str(obsid)))

        self.create_vlayer()
        self.select_features()
        feature_ids = [feature.id() for feature in self.vlayer.getFeatures()]

        reference_ids = (1, 2, 3)
        assert self.vlayer.isValid()
        assert len(feature_ids) == len(reference_ids)
        assert tuple(feature_ids) == reference_ids
        assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()])) == reference_ids
        assert tuple(sorted([x.id() for x in self.vlayer.getSelectedFeatures()])) == reference_ids
        assert tuple(sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)])) == reference_ids
        assert self.vlayer.featureCount() == 3

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.mock_instance_settings_database)
    def test_vlayer_strings(self, mock_skippopup, mock_messagebar):
        """

        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        for obsid in ['A', 'b', 'c1']:
            db_utils.sql_alter_db('''INSERT INTO obs_points (obsid) VALUES ('{}')'''.format(str(obsid)))

        self.create_vlayer()
        self.select_features()
        feature_ids = [feature.id() for feature in self.vlayer.getFeatures()]

        reference_ids = (1, 2, 3)
        assert self.vlayer.isValid()
        assert len(feature_ids) == len(reference_ids)
        assert tuple(feature_ids) == reference_ids
        assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()])) == reference_ids
        assert tuple(sorted([x.id() for x in self.vlayer.getSelectedFeatures()])) == reference_ids
        assert tuple(sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)])) == reference_ids
        assert self.vlayer.featureCount() == 3

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.mock_instance_settings_database)
    def test_vlayer_1000_features(self, mock_skippopup, mock_messagebar):
        """

        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        dbconnection = db_utils.DbConnectionManager()
        cur = dbconnection.cursor

        cur.execute('''BEGIN TRANSACTION;''')
        for obsid in range(1000):
            cur.execute('''INSERT INTO obs_points (obsid) VALUES ('{}');'''.format(str(obsid)))
        cur.execute('''END TRANSACTION;''')


        self.create_vlayer(no_print=True)
        self.select_features(no_print=True)
        feature_ids = [feature.id() for feature in self.vlayer.getFeatures()]



        reference_ids = tuple(range(1, 1001))

        print("First 10 ids: " + str(feature_ids[:10]))
        print("Last 10 ids: " + str(feature_ids[-10:]))
        print("First 10 reference_ids: " + str(reference_ids[:10]))
        print("Last 10 reference_ids: " + str(reference_ids[-10:]))

        assert self.vlayer.isValid()
        assert len(feature_ids) == len(reference_ids)
        assert tuple(feature_ids) == reference_ids
        assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()])) == reference_ids
        assert tuple(sorted([x.id() for x in self.vlayer.getSelectedFeatures()])) == reference_ids
        assert tuple(sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)])) == reference_ids
        assert self.vlayer.featureCount() == len(reference_ids)

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.mock_instance_settings_database)
    def test_vlayer_2000_ints(self, mock_skippopup, mock_messagebar):
        """

        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        dbconnection = db_utils.DbConnectionManager()
        cur = dbconnection.cursor

        cur.execute('''BEGIN TRANSACTION;''')
        for obsid in range(2000):
            cur.execute('''INSERT INTO obs_points (obsid) VALUES ('{}');'''.format(str(obsid)))
        cur.execute('''END TRANSACTION;''')


        self.create_vlayer(no_print=True)
        self.select_features(no_print=True)
        feature_ids = [feature.id() for feature in self.vlayer.getFeatures()]

        reference_ids = tuple(range(1, 2001))

        print("First 10 ids: " + str(feature_ids[:10]))
        print("Last 10 ids: " + str(feature_ids[-10:]))
        print("First 10 reference_ids: " + str(reference_ids[:10]))
        print("Last 10 reference_ids: " + str(reference_ids[-10:]))

        assert self.vlayer.isValid()
        assert len(feature_ids) == len(reference_ids)
        assert tuple(feature_ids) == reference_ids
        assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()])) == reference_ids
        assert tuple(sorted([x.id() for x in self.vlayer.getSelectedFeatures()])) == reference_ids
        assert tuple(sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)])) == reference_ids
        assert self.vlayer.featureCount() == len(reference_ids)

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.mock_instance_settings_database)
    def test_vlayer_2000_strings(self, mock_skippopup, mock_messagebar):
        """

        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        dbconnection = db_utils.DbConnectionManager()
        cur = dbconnection.cursor

        obsids = [letter + str(_int) for letter in string.ascii_letters for _int in range(80)]

        cur.execute('''BEGIN TRANSACTION;''')
        for obsid in obsids:
            cur.execute('''INSERT INTO obs_points (obsid) VALUES ('{}');'''.format(str(obsid)))
        cur.execute('''END TRANSACTION;''')
        dbconnection.commit()

        self.create_vlayer(no_print=True)
        self.select_features(no_print=True)
        feature_ids = [feature.id() for feature in self.vlayer.getFeatures()]

        reference_ids = tuple(range(1, len(obsids)+1))

        print("First 10 ids: " + str(feature_ids[:10]))
        print("Last 10 ids: " + str(feature_ids[-10:]))
        print("First 10 reference_ids: " + str(reference_ids[:10]))
        print("Last 10 reference_ids: " + str(reference_ids[-10:]))
        print(str(self.vlayer.featureCount()))

        assert self.vlayer.isValid()
        assert len(feature_ids) == len(reference_ids)
        assert tuple(feature_ids) == reference_ids
        assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()])) == reference_ids
        assert tuple(sorted([x.id() for x in self.vlayer.getSelectedFeatures()])) == reference_ids
        assert tuple(sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)])) == reference_ids
        assert self.vlayer.featureCount() == len(reference_ids)






    def tearDown(self):
        QgsProject.instance().addMapLayer(self.vlayer)
        QgsProject.instance().removeMapLayer(self.vlayer.id())
        super(self.__class__, self).tearDown()
Exemple #28
0
class TestVectorlayer(utils_for_tests.MidvattenTestSpatialiteDbSv):
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.
                mock_instance_settings_database)
    def create_vlayer(self, no_print=False):
        self.qgs = QgsApplication([], True)
        self.qgs.initQgis()

        dbconnection = db_utils.DbConnectionManager()
        uri = dbconnection.uri
        uri.setDataSource('', 'obs_points', 'geometry', '', 'obsid')
        dbtype = db_utils.get_dbtype(dbconnection.dbtype)
        self.vlayer = QgsVectorLayer(uri.uri(), 'TestLayer', dbtype)

        features = self.vlayer.getFeatures()
        feature_ids = [feature.id() for feature in features]

        if not no_print:
            print("1. Valid vlayer '{}'".format(self.vlayer.isValid()))
            print("2. feature_ids: " + str(feature_ids))
            print("5. QgsVectorLayer.getFeature(): " +
                  str([self.vlayer.getFeature(x).id() for x in feature_ids]))
            print("6. QgsVectorLayer.getFeature() type: " + str(
                [str(type(self.vlayer.getFeature(x))) for x in feature_ids]))
            print("7. QgsVectorLayer.getFeatures(): " +
                  str([x.id() for x in self.vlayer.getFeatures(feature_ids)]))
            print("8. QgsVectorLayer.featureCount(): " +
                  str(self.vlayer.featureCount()))

    def select_features(self, feature_ids=None, no_print=True):
        if feature_ids is None:
            features = self.vlayer.getFeatures()
            feature_ids = [feature.id() for feature in features]
        self.vlayer.selectByIds(feature_ids)

        if not no_print:
            print("3. QgsVectorLayer.selectedFeatureIds: " +
                  str(self.vlayer.selectedFeatureIds()))
            print("4. QgsVectorLayer.getSelectedFeatures: " +
                  str([x.id() for x in self.vlayer.getSelectedFeatures()]))

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.
                mock_instance_settings_database)
    def test_vlayer(self, mock_skippopup, mock_messagebar):
        """

        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        for obsid in [1, 2, 3]:
            db_utils.sql_alter_db(
                '''INSERT INTO obs_points (obsid) VALUES ({})'''.format(
                    str(obsid)))

        self.create_vlayer()
        self.select_features()
        feature_ids = [feature.id() for feature in self.vlayer.getFeatures()]

        reference_ids = (1, 2, 3)
        assert self.vlayer.isValid()
        assert len(feature_ids) == len(reference_ids)
        assert tuple(feature_ids) == reference_ids
        assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()
                             ])) == reference_ids
        assert tuple(
            sorted([x.id() for x in self.vlayer.getSelectedFeatures()
                    ])) == reference_ids
        assert tuple(
            sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)
                    ])) == reference_ids
        assert self.vlayer.featureCount() == 3

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.
                mock_instance_settings_database)
    def test_vlayer_other_ints_ids(self, mock_skippopup, mock_messagebar):
        """

        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        for obsid in [4, 5, 6]:
            db_utils.sql_alter_db(
                '''INSERT INTO obs_points (obsid) VALUES ({})'''.format(
                    str(obsid)))

        self.create_vlayer()
        self.select_features()
        feature_ids = [feature.id() for feature in self.vlayer.getFeatures()]

        reference_ids = (1, 2, 3)
        assert self.vlayer.isValid()
        assert len(feature_ids) == len(reference_ids)
        assert tuple(feature_ids) == reference_ids
        assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()
                             ])) == reference_ids
        assert tuple(
            sorted([x.id() for x in self.vlayer.getSelectedFeatures()
                    ])) == reference_ids
        assert tuple(
            sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)
                    ])) == reference_ids
        assert self.vlayer.featureCount() == 3

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.
                mock_instance_settings_database)
    def test_vlayer_strings(self, mock_skippopup, mock_messagebar):
        """

        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        for obsid in ['A', 'b', 'c1']:
            db_utils.sql_alter_db(
                '''INSERT INTO obs_points (obsid) VALUES ('{}')'''.format(
                    str(obsid)))

        self.create_vlayer()
        self.select_features()
        feature_ids = [feature.id() for feature in self.vlayer.getFeatures()]

        reference_ids = (1, 2, 3)
        assert self.vlayer.isValid()
        assert len(feature_ids) == len(reference_ids)
        assert tuple(feature_ids) == reference_ids
        assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()
                             ])) == reference_ids
        assert tuple(
            sorted([x.id() for x in self.vlayer.getSelectedFeatures()
                    ])) == reference_ids
        assert tuple(
            sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)
                    ])) == reference_ids
        assert self.vlayer.featureCount() == 3

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.
                mock_instance_settings_database)
    def test_vlayer_1000_features(self, mock_skippopup, mock_messagebar):
        """

        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        dbconnection = db_utils.DbConnectionManager()
        cur = dbconnection.cursor

        cur.execute('''BEGIN TRANSACTION;''')
        for obsid in range(1000):
            cur.execute(
                '''INSERT INTO obs_points (obsid) VALUES ('{}');'''.format(
                    str(obsid)))
        cur.execute('''END TRANSACTION;''')

        self.create_vlayer(no_print=True)
        self.select_features(no_print=True)
        feature_ids = [feature.id() for feature in self.vlayer.getFeatures()]

        reference_ids = tuple(range(1, 1001))

        print("First 10 ids: " + str(feature_ids[:10]))
        print("Last 10 ids: " + str(feature_ids[-10:]))
        print("First 10 reference_ids: " + str(reference_ids[:10]))
        print("Last 10 reference_ids: " + str(reference_ids[-10:]))

        assert self.vlayer.isValid()
        assert len(feature_ids) == len(reference_ids)
        assert tuple(feature_ids) == reference_ids
        assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()
                             ])) == reference_ids
        assert tuple(
            sorted([x.id() for x in self.vlayer.getSelectedFeatures()
                    ])) == reference_ids
        assert tuple(
            sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)
                    ])) == reference_ids
        assert self.vlayer.featureCount() == len(reference_ids)

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.
                mock_instance_settings_database)
    def test_vlayer_2000_ints(self, mock_skippopup, mock_messagebar):
        """

        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        dbconnection = db_utils.DbConnectionManager()
        cur = dbconnection.cursor

        cur.execute('''BEGIN TRANSACTION;''')
        for obsid in range(2000):
            cur.execute(
                '''INSERT INTO obs_points (obsid) VALUES ('{}');'''.format(
                    str(obsid)))
        cur.execute('''END TRANSACTION;''')

        self.create_vlayer(no_print=True)
        self.select_features(no_print=True)
        feature_ids = [feature.id() for feature in self.vlayer.getFeatures()]

        reference_ids = tuple(range(1, 2001))

        print("First 10 ids: " + str(feature_ids[:10]))
        print("Last 10 ids: " + str(feature_ids[-10:]))
        print("First 10 reference_ids: " + str(reference_ids[:10]))
        print("Last 10 reference_ids: " + str(reference_ids[-10:]))

        assert self.vlayer.isValid()
        assert len(feature_ids) == len(reference_ids)
        assert tuple(feature_ids) == reference_ids
        assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()
                             ])) == reference_ids
        assert tuple(
            sorted([x.id() for x in self.vlayer.getSelectedFeatures()
                    ])) == reference_ids
        assert tuple(
            sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)
                    ])) == reference_ids
        assert self.vlayer.featureCount() == len(reference_ids)

    @mock.patch('midvatten_utils.MessagebarAndLog')
    @mock.patch('stratigraphy.utils.pop_up_info', autospec=True)
    @mock.patch('db_utils.QgsProject.instance',
                utils_for_tests.MidvattenTestSpatialiteNotCreated.
                mock_instance_settings_database)
    def test_vlayer_2000_strings(self, mock_skippopup, mock_messagebar):
        """

        :param mock_skippopup:
        :param mock_messagebar:
        :return:
        """
        dbconnection = db_utils.DbConnectionManager()
        cur = dbconnection.cursor

        obsids = [
            letter + str(_int) for letter in string.ascii_letters
            for _int in range(80)
        ]

        cur.execute('''BEGIN TRANSACTION;''')
        for obsid in obsids:
            cur.execute(
                '''INSERT INTO obs_points (obsid) VALUES ('{}');'''.format(
                    str(obsid)))
        cur.execute('''END TRANSACTION;''')
        dbconnection.commit()

        self.create_vlayer(no_print=True)
        self.select_features(no_print=True)
        feature_ids = [feature.id() for feature in self.vlayer.getFeatures()]

        reference_ids = tuple(range(1, len(obsids) + 1))

        print("First 10 ids: " + str(feature_ids[:10]))
        print("Last 10 ids: " + str(feature_ids[-10:]))
        print("First 10 reference_ids: " + str(reference_ids[:10]))
        print("Last 10 reference_ids: " + str(reference_ids[-10:]))
        print(str(self.vlayer.featureCount()))

        assert self.vlayer.isValid()
        assert len(feature_ids) == len(reference_ids)
        assert tuple(feature_ids) == reference_ids
        assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()
                             ])) == reference_ids
        assert tuple(
            sorted([x.id() for x in self.vlayer.getSelectedFeatures()
                    ])) == reference_ids
        assert tuple(
            sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)
                    ])) == reference_ids
        assert self.vlayer.featureCount() == len(reference_ids)

    def tearDown(self):
        QgsProject.instance().addMapLayer(self.vlayer)
        QgsProject.instance().removeMapLayer(self.vlayer.id())
        super(self.__class__, self).tearDown()