Example #1
0
    def __build_data(self):

        req = QgsFeatureRequest()
        if self.__filter_expression is not None:
            req.setFilterExpression(self.__filter_expression)

        # Get unit of the first feature if needed
        if self.__uom is not None and self.__uom.startswith("@"):
            req2 = QgsFeatureRequest(req)
            req2.setLimit(1)
            for f in self.__layer.getFeatures(req):
                self.__uom = f[self.__uom[1:]]
                break

        req.setSubsetOfAttributes([self.__x_fieldname, self.__y_fieldname],
                                  self.__layer.fields())
        # Do not forget to add an index on this field to speed up ordering
        req.addOrderBy(self.__x_fieldname)

        xy_values = [
            (f[self.__x_fieldname], f[self.__y_fieldname]
             if f[self.__y_fieldname] is not None else self.__nodata_value)
            for f in self.__layer.getFeatures(req)
        ]

        self.__x_values = [coord[0] for coord in xy_values]
        self.__y_values = [coord[1] for coord in xy_values]

        self.__x_min, self.__x_max = (min(self.__x_values), max(
            self.__x_values)) if self.__x_values else (None, None)
        self.__y_min, self.__y_max = (min(self.__y_values), max(
            self.__y_values)) if self.__y_values else (None, None)

        self.data_modified.emit()
Example #2
0
def print_attribute_table(layer, limit=-1):
    """Print the attribute table in the console.

    :param layer: The layer to print.
    :type layer: QgsVectorLayer

    :param limit: The limit in the query.
    :type limit: integer
    """
    if layer.wkbType() == QGis.WKBNoGeometry:
        geometry = False
    else:
        geometry = True

    headers = []
    if geometry:
        headers.append('geom')
    headers.extend(
        [f.name() + ' : ' + str(f.type()) for f in layer.fields().toList()])

    request = QgsFeatureRequest()
    request.setLimit(limit)
    data = []
    for feature in layer.getFeatures(request):
        attributes = []
        if geometry:
            attributes.append(feature.geometry().type())
        attributes.extend(feature.attributes())
        data.append(attributes)

    print pretty_table(data, headers)
Example #3
0
def print_attribute_table(layer, limit=-1):
    """Print the attribute table in the console.

    :param layer: The layer to print.
    :type layer: QgsVectorLayer

    :param limit: The limit in the query.
    :type limit: integer
    """
    if layer.wkbType() in [
            QgsWkbTypes.NullGeometry, QgsWkbTypes.UnknownGeometry
    ]:
        geometry = False
    else:
        geometry = True

    headers = []
    if geometry:
        headers.append('geom')
    headers.extend(
        [f.name() + ' : ' + str(f.type()) for f in layer.fields().toList()])

    request = QgsFeatureRequest()
    request.setLimit(limit)
    data = []
    for feature in layer.getFeatures(request):
        attributes = []
        if geometry:
            attributes.append(feature.geometry().type())
        attributes.extend(feature.attributes())
        data.append(attributes)

    print((pretty_table(data, headers)))
 def observation_exists(layer, feature_id) -> Tuple[bool, Optional[QgsFeature]]:
     """ Check if the given observation exists. """
     request = QgsFeatureRequest()
     request.setLimit(1)
     request.setSubsetOfAttributes(['id'], layer.fields())
     request.setFilterExpression('"id" = {}'.format(feature_id))
     join_feature = QgsFeature()
     if layer.getFeatures(request).nextFeature(join_feature):
         return True, join_feature
     return False, None
Example #5
0
 def layers(self, feature=None):
     if feature is None:
         request = QgsFeatureRequest()
         request.setFlags(QgsFeatureRequest.NoGeometry)
         request.setSubsetOfAttributes(["layers"], self._layer.fields())
         request.setLimit(1)
         feature = next(self._layer.getFeatures(request))
     value = feature.attribute("layers")
     if is_null(value) or value == "":
         return []
     return value.split(",")
 def district_name_exists(self, district) -> bool:
     request = QgsFeatureRequest()
     request.setFilterExpression(QgsExpression.createFieldEqualityExpression(self.title_field, district))
     request.setFlags(QgsFeatureRequest.NoGeometry)
     request.setSubsetOfAttributes([])
     request.setLimit(1)
     try:
         next(self.source_layer.getFeatures(request))
     except StopIteration:
         return False
     return True
Example #7
0
 def get_estimated_population(self, electorate_id) -> int:
     """
     Returns the estimated (offline) population for the district
     :param electorate_id: electorate code/id
     """
     # lookup matching feature
     request = QgsFeatureRequest()
     request.setFilterExpression(QgsExpression.createFieldEqualityExpression(self.source_field, electorate_id))
     request.setFlags(QgsFeatureRequest.NoGeometry)
     request.setSubsetOfAttributes([self.estimated_pop_field_index])
     request.setLimit(1)
     f = next(self.source_layer.getFeatures(request))
     return f[self.estimated_pop_field_index]
Example #8
0
 def get_district_type(self, electorate_id) -> str:
     """
     Returns the district type (GN/GS/M) for the specified district
     :param electorate_id: electorate id
     """
     # lookup matching feature
     request = QgsFeatureRequest()
     request.setFilterExpression(QgsExpression.createFieldEqualityExpression(self.source_field, electorate_id))
     request.setFlags(QgsFeatureRequest.NoGeometry)
     request.setSubsetOfAttributes([self.type_field_index])
     request.setLimit(1)
     f = next(self.source_layer.getFeatures(request))
     return f[self.type_field_index]
Example #9
0
    def insert_scenario(layer: QgsVectorLayer, name: str) -> int:
        """ Insert the new scenario and get its ID. """
        feature = QgsFeature(layer.fields())
        feature.setAttribute('nom', name)
        with edit(layer):
            layer.addFeature(feature)

        request = QgsFeatureRequest()
        request.setLimit(1)
        request.addOrderBy('id', False)
        feature = QgsFeature()
        layer.getFeatures(request).nextFeature(feature)
        return feature['id']
    def get_district_title(self, district):
        if self.title_field == self.source_field:
            return super().get_district_title(district)

        # lookup matching feature
        request = QgsFeatureRequest()
        request.setFilterExpression(QgsExpression.createFieldEqualityExpression(self.source_field, district))
        request.setFlags(QgsFeatureRequest.NoGeometry)
        request.setSubsetOfAttributes([self.title_field_index])
        request.setLimit(1)
        try:
            f = next(self.source_layer.getFeatures(request))
        except StopIteration:
            return super().get_district_title(district)
        return f[self.title_field_index]
Example #11
0
    def get_code_for_electorate(self, electorate_id):
        """
        Returns the electorate code for a given electorate_id
        :param electorate_id: electorate id
        """
        code_field_index = self.source_layer.fields().lookupField('code')
        assert code_field_index >= 0

        request = QgsFeatureRequest()
        request.setFilterFid(electorate_id)
        request.setFlags(QgsFeatureRequest.NoGeometry)
        request.setSubsetOfAttributes([code_field_index])
        request.setLimit(1)
        f = next(self.source_layer.getFeatures(request))
        return f[code_field_index]
Example #12
0
    def get_quota_for_district_type(self, district_type: str) -> int:
        """
        Returns the quota for the specified district type
        :param district_type: district type, e.g. "GS"
        """
        quota_field_index = self.quota_layer.fields().lookupField('quota')
        assert quota_field_index >= 0

        request = QgsFeatureRequest()
        request.setFilterExpression(QgsExpression.createFieldEqualityExpression('type', district_type))
        request.setFlags(QgsFeatureRequest.NoGeometry)
        request.setSubsetOfAttributes([quota_field_index])
        request.setLimit(1)
        f = next(self.quota_layer.getFeatures(request))
        return f[quota_field_index]
Example #13
0
    def feature_exists(layer, habitat_id, pression_id, scenario_id) -> Tuple[bool, Optional[QgsFeature]]:
        """ Check if the given feature exists. """
        request = QgsFeatureRequest()
        request.setLimit(1)
        request.setFilterExpression(
            '"habitat_id" = {habitat} AND "pression_id" = {pression} AND "scenario_id" = {scenario}'.format(
                habitat=habitat_id,
                pression=pression_id,
                scenario=scenario_id,
            ))
        feature = QgsFeature()
        if layer.getFeatures(request).nextFeature(feature):
            return True, feature

        return False, None
    def get_scenario(self, scenario) -> QgsFeature:
        """
        Returns the feature corresponding to the given scenario
        :param scenario: scenario id to get feature for
        """

        # lookup matching feature
        request = QgsFeatureRequest()
        request.setFilterExpression(
            QgsExpression.createFieldEqualityExpression(
                self.id_field, scenario))
        request.setFlags(QgsFeatureRequest.NoGeometry)
        request.setLimit(1)
        f = next(self.source_layer.getFeatures(request))
        return f
Example #15
0
 def get_stats_nz_calculations(self, electorate_id) -> dict:
     """
     Returns a dictionary of Stats NZ calculations for the district
     :param electorate_id: electorate code/id
     """
     # lookup matching feature
     request = QgsFeatureRequest()
     request.setFilterExpression(QgsExpression.createFieldEqualityExpression(self.source_field, electorate_id))
     request.setFlags(QgsFeatureRequest.NoGeometry)
     request.setSubsetOfAttributes(
         [self.stats_nz_var_23_field_index, self.stats_nz_var_20_field_index, self.stats_nz_pop_field_index])
     request.setLimit(1)
     f = next(self.source_layer.getFeatures(request))
     return {'currentPopulation': f[self.stats_nz_pop_field_index],
             'varianceYear1': f[self.stats_nz_var_20_field_index],
             'varianceYear2': f[self.stats_nz_var_23_field_index]}
 def scenario_exists(self, scenario_id) -> bool:
     """
     Returns true if the given scenario exists
     :param scenario_id: ID for scenario
     """
     request = QgsFeatureRequest()
     request.setFlags(QgsFeatureRequest.NoGeometry)
     request.setSubsetOfAttributes([])
     request.setFilterExpression(
         QgsExpression.createFieldEqualityExpression(
             self.id_field, scenario_id))
     request.setLimit(1)
     for f in self.source_layer.getFeatures(request):  # pylint: disable=unused-variable
         # found a matching feature
         return True
     return False
    def get_scenario_name(self, scenario) -> str:
        """
        Returns a user-friendly name corresponding to the given scenario
        :param scenario: scenario id to get name for
        """

        # lookup matching feature
        request = QgsFeatureRequest()
        request.setFilterExpression(
            QgsExpression.createFieldEqualityExpression(
                self.id_field, scenario))
        request.setFlags(QgsFeatureRequest.NoGeometry)
        request.setSubsetOfAttributes([self.name_field_index])
        request.setLimit(1)
        f = next(self.source_layer.getFeatures(request))
        return f[self.name_field_index]
 def scenario_name_exists(self, new_scenario_name: str) -> bool:
     """
     Returns true if the given scenario name already exists
     :param new_scenario_name: name of scenario to test
     """
     request = QgsFeatureRequest()
     request.setFlags(QgsFeatureRequest.NoGeometry)
     request.setSubsetOfAttributes([])
     request.setFilterExpression(
         QgsExpression.createFieldEqualityExpression(
             self.name_field, new_scenario_name))
     request.setLimit(1)
     for f in self.source_layer.getFeatures(request):  # pylint: disable=unused-variable
         # found a matching feature
         return True
     return False
Example #19
0
    def runGetFeatureTests(self, source):
        FeatureSourceTestCase.runGetFeatureTests(self, source)

        # combination of an uncompilable expression and limit
        feature = next(self.vl.getFeatures('pk=4'))
        context = QgsExpressionContext()
        scope = QgsExpressionContextScope()
        scope.setVariable('parent', feature)
        context.appendScope(scope)

        request = QgsFeatureRequest()
        request.setExpressionContext(context)
        request.setFilterExpression('"pk" = attribute(@parent, \'pk\')')
        request.setLimit(1)

        values = [f['pk'] for f in self.vl.getFeatures(request)]
        self.assertEqual(values, [4])
Example #20
0
    def runGetFeatureTests(self, source):
        FeatureSourceTestCase.runGetFeatureTests(self, source)

        # combination of an uncompilable expression and limit
        feature = next(self.vl.getFeatures('pk=4'))
        context = QgsExpressionContext()
        scope = QgsExpressionContextScope()
        scope.setVariable('parent', feature)
        context.appendScope(scope)

        request = QgsFeatureRequest()
        request.setExpressionContext(context)
        request.setFilterExpression('"pk" = attribute(@parent, \'pk\')')
        request.setLimit(1)

        values = [f['pk'] for f in self.vl.getFeatures(request)]
        self.assertEqual(values, [4])
Example #21
0
    def flag_stats_nz_updating(self, electorate_id):
        """
        Flags an electorate's Statistics NZ api calculations as being currently updated
        :param electorate_id: electorate to update
        """

        # get feature ID
        request = QgsFeatureRequest()
        request.setFilterExpression(QgsExpression.createFieldEqualityExpression(self.source_field, electorate_id))
        request.setFlags(QgsFeatureRequest.NoGeometry)
        request.setSubsetOfAttributes([])
        request.setLimit(1)
        f = next(self.source_layer.getFeatures(request))

        self.source_layer.dataProvider().changeAttributeValues({f.id(): {self.stats_nz_pop_field_index: -1,
                                                                         self.stats_nz_var_20_field_index: NULL,
                                                                         self.stats_nz_var_23_field_index: NULL}})
Example #22
0
    def __build_data(self):

        req = QgsFeatureRequest()
        if self.__filter_expression is not None:
            req.setFilterExpression(self.__filter_expression)

        # Get unit of the first feature if needed
        if self.__uom is not None and self.__uom.startswith("@"):
            request_unit = QgsFeatureRequest(req)
            request_unit.setLimit(1)
            for f in self.__layer.getFeatures(request_unit):
                self.__uom = f[self.__uom[1:]]
                break

        req.setSubsetOfAttributes([self.__x_fieldname, self.__y_fieldname],
                                  self.__layer.fields())
        # Do not forget to add an index on this field to speed up ordering
        req.addOrderBy(self.__x_fieldname)

        def is_null(v):
            return isinstance(v, QVariant) and v.isNull()

        if self.__nodata_value is not None:
            # replace null values by a 'Nodata' value
            xy_values = [
                (f[self.__x_fieldname], f[self.__y_fieldname] if
                 not is_null(f[self.__y_fieldname]) else self.__nodata_value)
                for f in self.__layer.getFeatures(req)
            ]
        else:
            # do not include null values
            xy_values = [(f[self.__x_fieldname], f[self.__y_fieldname])
                         for f in self.__layer.getFeatures(req)
                         if not is_null(f[self.__y_fieldname])]

        self.__x_values = [coord[0] for coord in xy_values]
        self.__y_values = [coord[1] for coord in xy_values]

        self.__x_min, self.__x_max = (min(self.__x_values), max(
            self.__x_values)) if self.__x_values else (None, None)
        self.__y_min, self.__y_max = (min(self.__y_values), max(
            self.__y_values)) if self.__y_values else (None, None)

        self.data_modified.emit()
Example #23
0
    def update_stats_nz_values(self, electorate_id, results: dict):
        """
        Updates an electorate's stored Statistics NZ api calculations
        :param electorate_id: electorate to update
        :param results: results dictionary from stats API
        """

        # get feature ID
        request = QgsFeatureRequest()
        request.setFilterExpression(QgsExpression.createFieldEqualityExpression(self.source_field, electorate_id))
        request.setFlags(QgsFeatureRequest.NoGeometry)
        request.setSubsetOfAttributes([])
        request.setLimit(1)
        f = next(self.source_layer.getFeatures(request))

        self.source_layer.dataProvider().changeAttributeValues(
            {f.id(): {self.stats_nz_pop_field_index: results['currentPopulation'],
                      self.stats_nz_var_20_field_index: results['varianceYear1'],
                      self.stats_nz_var_23_field_index: results['varianceYear2']}})
Example #24
0
    def search_data_source(self, search_expression, sort_map):
        """
        Searches the data source using the specified search expression.
        :param search_expression: Search expression either as a string or
        instance of QgsExpression.
        :type search_expression: str or QgsExpression
        :param sort_map: List containing a definition of column sorting.
        :type sort_map: list
        :return: Returns a list containing search results consisting of
        QgsFeature objects.
        :rtype: list
        """
        results = []
        if not self._vector_layer.isValid():
            raise FltsSearchException(
                'Search cannot be performed, data source is invalid.')
        if isinstance(search_expression, basestring):
            search_expression = QgsExpression(search_expression)

        # Assert if there are errors in the expression
        if search_expression.hasParserError():
            raise FltsSearchException(search_expression.parserErrorString())

        fr = QgsFeatureRequest(search_expression)
        if not self._config.limit:
            limit = -1
        else:
            limit = self._config.limit
        fr.setLimit(limit)

        # Set sorting if specified.
        if sort_map:
            for s in sort_map:
                ascending = True if s[1] == 0 else False
                fr.addOrderBy(s[0], ascending)

        feat_iter = self._vector_layer.getFeatures(fr)
        for f in feat_iter:
            results.append(f)

        return results
Example #25
0
 def limit_features(self, new_feature):
     feature_count = self.pr.featureCount()
     if feature_count < self.limit:
         self.pr.addFeatures([new_feature])
         progress = (feature_count * 100) / self.limit
         self.dlg.streamingPb.setValue(progress)
     else:
         self.dlg.streamingPb.setRange(0, 0)
         feats_request = QgsFeatureRequest()
         feats_request.addOrderBy('time', ascending=False)
         feats_request.setLimit(2000)
         features_iterator = self.pr.getFeatures(feats_request)
         if not features_iterator.isValid():
             return
         last_feature = next(
             itertools.islice(features_iterator, feature_count - 1,
                              feature_count))
         last_feature_id = last_feature.id()
         self.startEditing()
         self.deleteFeature(last_feature_id)
         self.pr.addFeatures([new_feature])
Example #26
0
def search_gpkg(search_text, search_field, echo_search_column, display_fields,
                extra_expr_columns, layer, limit):
    wildcarded_search_string = ''
    for part in search_text.split():
        wildcarded_search_string += '%' + part
    wildcarded_search_string += '%'
    expr_str = "{0} ILIKE '{1}'".format(search_field, wildcarded_search_string)
    expr = QgsExpression(expr_str)
    req = QgsFeatureRequest(expr)
    limit = limit if is_number(limit) else None
    if limit:
        req.setLimit(int(limit))
    it = layer.getFeatures(req)
    result = []

    for f in it:
        feature_info = []
        geom = f.geometry().asWkt()
        epsg = layer.crs().authid()
        feature_info.append(geom)
        feature_info.append(epsg)
        available_fields = [field.name() for field in f.fields()]

        display_info = []
        if echo_search_column:
            display_info.append(str(f[search_field]))
        for field_name in display_fields:
            if f[field_name]:
                display_info.append(str(f[field_name]))
        feature_info.append(", ".join(display_info))

        for field_name in extra_expr_columns:
            if field_name in available_fields:
                feature_info.append(f[field_name])
            else:
                feature_info.append("")
        result.append(feature_info)
    return result
Example #27
0
    def create_widget(self):
        request = QgsFeatureRequest()
        request.setLimit(1)
        feature = next(self.layer.getFeatures(request))

        section = PreCourlisFileLine(self.layer).section_from_feature(feature)
        section.feature = feature

        widget = GraphWidget(None)

        model = PointsTableModel(widget)
        model.set_section(section)
        sel_model = QtCore.QItemSelectionModel(model, widget)
        widget.set_selection_model(sel_model)

        widget.set_sections(
            layer=self.layer,
            feature=feature,
            previous_section=None,
            current_section=section,
            next_section=None,
        )
        return widget
Example #28
0
def count_qgis_features(qgis_layer,
                        qgis_feature_request=None,
                        bbox_filter=None,
                        attribute_filters=None,
                        search_filter=None,
                        extra_expression=None,
                        extra_subset_string=None,
                        **kwargs):
    """Returns a list of QgsFeatures from the QGIS vector layer,
    with optional filter options.

    The API can be used in two distinct ways (that are not mutually exclusive):

    1. pass in a pre-configured QgsFeatureRequest instance
    2. pass a series of filter attributes and let this method configure
    the QgsFeatureRequest.

    :param qgis_layer: the QGIS vector layer instance
    :type qgis_layer: QgsVectorLayer
    :param qgis_feature_request: the QGIS feature request
    :type qgis_feature_request: QgsFeatureRequest, optional
    :param bbox_filter: BBOX filter in layer's CRS, defaults to None
    :type bbox_filter: QgsRectangle, optional
    :param attribute_filters: dictionary of attribute filters combined with AND, defaults to None
    :type attribute_filters: dict, optional
    :param search_filter: string filter for all fields
    :type search_filter: str, optional
    :param: exclude_fields: list of fields to exclude from returned data, '__all__' for no attributes
    :param: extra_expression: extra expression for filtering features
    :type: extra_expression: str, optional
    :param: extra_subset_string: extra subset string (provider side WHERE condition) for filtering features
    :type: extra_subset_string: str, optional
    :return: list of features
    :rtype: QgsFeature list
    """

    # Remove no_filters condition because featureCount()
    # is cached,  so it could fail on multi-processes deploy
    # ------------------------------------------------------

    # Fast track for no filters
    # no_filters = (attribute_filters is None
    #     and (bbox_filter is None or bbox_filter.isEmpty()) and
    #     attribute_filters is None and
    #     extra_expression is None and
    #     extra_subset_string is None)
    #
    # if qgis_feature_request is not None:
    #     no_filters = (no_filters and
    #         qgis_feature_request.filterRect().isEmpty() and
    #         qgis_feature_request.filterType() == QgsFeatureRequest.FilterNone)
    # else:
    if not qgis_feature_request:
        qgis_feature_request = QgsFeatureRequest()

    # if no_filters:
    #     # Try to patch a possible Oracle views QGIS featureCount bug.
    #     qgs_fc = qgis_layer.featureCount()
    #     if qgs_fc != -1:
    #         return qgis_layer.featureCount()

    qgis_feature_request.setNoAttributes()
    if qgis_feature_request.limit() != -1:
        qgis_feature_request = QgsFeatureRequest(qgis_feature_request)
        qgis_feature_request.setLimit(-1)

    return len(
        __get_qgis_features(
            qgis_layer,
            qgis_feature_request,
            bbox_filter,
            attribute_filters,
            search_filter,
            False,  #with_geometry,
            None,  #page,
            None,  #page_size,
            None,  #ordering,
            None,  #exclude_fields,
            extra_expression,
            extra_subset_string))
Example #29
0
    def runGetFeatureTests(self, provider):
        assert len([f for f in provider.getFeatures()]) == 5
        self.assert_query(provider, 'name ILIKE \'QGIS\'', [])
        self.assert_query(provider, '"name" IS NULL', [5])
        self.assert_query(provider, '"name" IS NOT NULL', [1, 2, 3, 4])
        self.assert_query(provider, '"name" NOT LIKE \'Ap%\'', [1, 3, 4])
        self.assert_query(provider, '"name" NOT ILIKE \'QGIS\'', [1, 2, 3, 4])
        self.assert_query(provider, '"name" NOT ILIKE \'pEAR\'', [1, 2, 4])
        self.assert_query(provider, 'name = \'Apple\'', [2])
        self.assert_query(provider, 'name <> \'Apple\'', [1, 3, 4])
        self.assert_query(provider, 'name = \'apple\'', [])
        self.assert_query(provider, '"name" <> \'apple\'', [1, 2, 3, 4])
        self.assert_query(provider, '(name = \'Apple\') is not null', [1, 2, 3, 4])
        self.assert_query(provider, 'name LIKE \'Apple\'', [2])
        self.assert_query(provider, 'name LIKE \'aPple\'', [])
        self.assert_query(provider, 'name ILIKE \'aPple\'', [2])
        self.assert_query(provider, 'name ILIKE \'%pp%\'', [2])
        self.assert_query(provider, 'cnt > 0', [1, 2, 3, 4])
        self.assert_query(provider, '-cnt > 0', [5])
        self.assert_query(provider, 'cnt < 0', [5])
        self.assert_query(provider, '-cnt < 0', [1, 2, 3, 4])
        self.assert_query(provider, 'cnt >= 100', [1, 2, 3, 4])
        self.assert_query(provider, 'cnt <= 100', [1, 5])
        self.assert_query(provider, 'pk IN (1, 2, 4, 8)', [1, 2, 4])
        self.assert_query(provider, 'cnt = 50 * 2', [1])
        self.assert_query(provider, 'cnt = 150 / 1.5', [1])
        self.assert_query(provider, 'cnt = 1000 / 10', [1])
        self.assert_query(provider, 'cnt = 1000/11+10', []) # checks that provider isn't rounding int/int
        self.assert_query(provider, 'pk = 9 // 4', [2]) # int division
        self.assert_query(provider, 'cnt = 99 + 1', [1])
        self.assert_query(provider, 'cnt = 101 - 1', [1])
        self.assert_query(provider, 'cnt - 1 = 99', [1])
        self.assert_query(provider, '-cnt - 1 = -101', [1])
        self.assert_query(provider, '-(-cnt) = 100', [1])
        self.assert_query(provider, '-(cnt) = -(100)', [1])
        self.assert_query(provider, 'cnt + 1 = 101', [1])
        self.assert_query(provider, 'cnt = 1100 % 1000', [1])
        self.assert_query(provider, '"name" || \' \' || "name" = \'Orange Orange\'', [1])
        self.assert_query(provider, '"name" || \' \' || "cnt" = \'Orange 100\'', [1])
        self.assert_query(provider, '\'x\' || "name" IS NOT NULL', [1, 2, 3, 4])
        self.assert_query(provider, '\'x\' || "name" IS NULL', [5])
        self.assert_query(provider, 'cnt = 10 ^ 2', [1])
        self.assert_query(provider, '"name" ~ \'[OP]ra[gne]+\'', [1])
        self.assert_query(provider, '"name"="name2"', [2, 4])  # mix of matched and non-matched case sensitive names
        self.assert_query(provider, 'true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'false', [])

        # Three value logic
        self.assert_query(provider, 'false and false', [])
        self.assert_query(provider, 'false and true', [])
        self.assert_query(provider, 'false and NULL', [])
        self.assert_query(provider, 'true and false', [])
        self.assert_query(provider, 'true and true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'true and NULL', [])
        self.assert_query(provider, 'NULL and false', [])
        self.assert_query(provider, 'NULL and true', [])
        self.assert_query(provider, 'NULL and NULL', [])
        self.assert_query(provider, 'false or false', [])
        self.assert_query(provider, 'false or true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'false or NULL', [])
        self.assert_query(provider, 'true or false', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'true or true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'true or NULL', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'NULL or false', [])
        self.assert_query(provider, 'NULL or true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'NULL or NULL', [])
        self.assert_query(provider, 'not true', [])
        self.assert_query(provider, 'not false', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'not null', [])

        # not
        self.assert_query(provider, 'not name = \'Apple\'', [1, 3, 4])
        self.assert_query(provider, 'not name IS NULL', [1, 2, 3, 4])
        self.assert_query(provider, 'not name = \'Apple\' or name = \'Apple\'', [1, 2, 3, 4])
        self.assert_query(provider, 'not name = \'Apple\' or not name = \'Apple\'', [1, 3, 4])
        self.assert_query(provider, 'not name = \'Apple\' and pk = 4', [4])
        self.assert_query(provider, 'not name = \'Apple\' and not pk = 4', [1, 3])
        self.assert_query(provider, 'not pk IN (1, 2, 4, 8)', [3, 5])

        # type conversion - QGIS expressions do not mind that we are comparing a string
        # against numeric literals
        self.assert_query(provider, 'num_char IN (2, 4, 5)', [2, 4, 5])

        #function
        self.assert_query(provider, 'sqrt(pk) >= 2', [4, 5])
        self.assert_query(provider, 'radians(cnt) < 2', [1, 5])
        self.assert_query(provider, 'degrees(pk) <= 200', [1, 2, 3])
        self.assert_query(provider, 'abs(cnt) <= 200', [1, 2, 5])
        self.assert_query(provider, 'cos(pk) < 0', [2, 3, 4])
        self.assert_query(provider, 'sin(pk) < 0', [4, 5])
        self.assert_query(provider, 'tan(pk) < 0', [2, 3, 5])
        self.assert_query(provider, 'acos(-1) < pk', [4, 5])
        self.assert_query(provider, 'asin(1) < pk', [2, 3, 4, 5])
        self.assert_query(provider, 'atan(3.14) < pk', [2, 3, 4, 5])
        self.assert_query(provider, 'atan2(3.14, pk) < 1', [3, 4, 5])
        self.assert_query(provider, 'exp(pk) < 10', [1, 2])
        self.assert_query(provider, 'ln(pk) <= 1', [1, 2])
        self.assert_query(provider, 'log(3, pk) <= 1', [1, 2, 3])
        self.assert_query(provider, 'log10(pk) < 0.5', [1, 2, 3])
        self.assert_query(provider, 'round(3.14) <= pk', [3, 4, 5])
        self.assert_query(provider, 'round(0.314,1) * 10 = pk', [3])
        self.assert_query(provider, 'floor(3.14) <= pk', [3, 4, 5])
        self.assert_query(provider, 'ceil(3.14) <= pk', [4, 5])
        self.assert_query(provider, 'pk < pi()', [1, 2, 3])

        self.assert_query(provider, 'round(cnt / 66.67) <= 2', [1, 5])
        self.assert_query(provider, 'floor(cnt / 66.67) <= 2', [1, 2, 5])
        self.assert_query(provider, 'ceil(cnt / 66.67) <= 2', [1, 5])
        self.assert_query(provider, 'pk < pi() / 2', [1])
        self.assert_query(provider, 'pk = char(51)', [3])
        self.assert_query(provider, 'pk = coalesce(NULL,3,4)', [3])
        self.assert_query(provider, 'lower(name) = \'apple\'', [2])
        self.assert_query(provider, 'upper(name) = \'APPLE\'', [2])
        self.assert_query(provider, 'name = trim(\'   Apple   \')', [2])

        # geometry
        # azimuth and touches tests are deactivated because they do not pass for WFS provider
        #self.assert_query(provider, 'azimuth($geometry,geom_from_wkt( \'Point (-70 70)\')) < pi()', [1, 5])
        self.assert_query(provider, 'x($geometry) < -70', [1, 5])
        self.assert_query(provider, 'y($geometry) > 70', [2, 4, 5])
        self.assert_query(provider, 'xmin($geometry) < -70', [1, 5])
        self.assert_query(provider, 'ymin($geometry) > 70', [2, 4, 5])
        self.assert_query(provider, 'xmax($geometry) < -70', [1, 5])
        self.assert_query(provider, 'ymax($geometry) > 70', [2, 4, 5])
        self.assert_query(provider, 'disjoint($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', [4, 5])
        self.assert_query(provider, 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', [1, 2])
        #self.assert_query(provider, 'touches($geometry,geom_from_wkt( \'Polygon ((-70.332 66.33, -65.32 66.33, -65.32 78.3, -70.332 78.3, -70.332 66.33))\'))', [1, 4])
        self.assert_query(provider, 'contains(geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'),$geometry)', [1, 2])
        self.assert_query(provider, 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7', [4, 5])
        self.assert_query(provider, 'intersects($geometry,geom_from_gml( \'<gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon>\'))', [1, 2])

        # combination of an uncompilable expression and limit
        feature = next(self.vl.getFeatures('pk=4'))
        context = QgsExpressionContext()
        scope = QgsExpressionContextScope()
        scope.setVariable('parent', feature)
        context.appendScope(scope)

        request = QgsFeatureRequest()
        request.setExpressionContext(context)
        request.setFilterExpression('"pk" = attribute(@parent, \'pk\')')
        request.setLimit(1)

        values = [f['pk'] for f in self.vl.getFeatures(request)]
        self.assertEqual(values, [4])
Example #30
0
    def runGetFeatureTests(self, provider):
        assert len([f for f in provider.getFeatures()]) == 5
        self.assert_query(provider, 'name ILIKE \'QGIS\'', [])
        self.assert_query(provider, '"name" IS NULL', [5])
        self.assert_query(provider, '"name" IS NOT NULL', [1, 2, 3, 4])
        self.assert_query(provider, '"name" NOT LIKE \'Ap%\'', [1, 3, 4])
        self.assert_query(provider, '"name" NOT ILIKE \'QGIS\'', [1, 2, 3, 4])
        self.assert_query(provider, '"name" NOT ILIKE \'pEAR\'', [1, 2, 4])
        self.assert_query(provider, 'name = \'Apple\'', [2])
        self.assert_query(provider, 'name <> \'Apple\'', [1, 3, 4])
        self.assert_query(provider, 'name = \'apple\'', [])
        self.assert_query(provider, '"name" <> \'apple\'', [1, 2, 3, 4])
        self.assert_query(provider, '(name = \'Apple\') is not null',
                          [1, 2, 3, 4])
        self.assert_query(provider, 'name LIKE \'Apple\'', [2])
        self.assert_query(provider, 'name LIKE \'aPple\'', [])
        self.assert_query(provider, 'name ILIKE \'aPple\'', [2])
        self.assert_query(provider, 'name ILIKE \'%pp%\'', [2])
        self.assert_query(provider, 'cnt > 0', [1, 2, 3, 4])
        self.assert_query(provider, '-cnt > 0', [5])
        self.assert_query(provider, 'cnt < 0', [5])
        self.assert_query(provider, '-cnt < 0', [1, 2, 3, 4])
        self.assert_query(provider, 'cnt >= 100', [1, 2, 3, 4])
        self.assert_query(provider, 'cnt <= 100', [1, 5])
        self.assert_query(provider, 'pk IN (1, 2, 4, 8)', [1, 2, 4])
        self.assert_query(provider, 'cnt = 50 * 2', [1])
        self.assert_query(provider, 'cnt = 99 + 1', [1])
        self.assert_query(provider, 'cnt = 101 - 1', [1])
        self.assert_query(provider, 'cnt - 1 = 99', [1])
        self.assert_query(provider, '-cnt - 1 = -101', [1])
        self.assert_query(provider, '-(-cnt) = 100', [1])
        self.assert_query(provider, '-(cnt) = -(100)', [1])
        self.assert_query(provider, 'cnt + 1 = 101', [1])
        self.assert_query(provider, 'cnt = 1100 % 1000', [1])
        self.assert_query(provider,
                          '"name" || \' \' || "name" = \'Orange Orange\'', [1])
        self.assert_query(provider,
                          '"name" || \' \' || "cnt" = \'Orange 100\'', [1])
        self.assert_query(provider, '\'x\' || "name" IS NOT NULL',
                          [1, 2, 3, 4])
        self.assert_query(provider, '\'x\' || "name" IS NULL', [5])
        self.assert_query(provider, 'cnt = 10 ^ 2', [1])
        self.assert_query(provider, '"name" ~ \'[OP]ra[gne]+\'', [1])
        self.assert_query(
            provider, '"name"="name2"',
            [2, 4])  # mix of matched and non-matched case sensitive names
        self.assert_query(provider, 'true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'false', [])

        # Three value logic
        self.assert_query(provider, 'false and false', [])
        self.assert_query(provider, 'false and true', [])
        self.assert_query(provider, 'false and NULL', [])
        self.assert_query(provider, 'true and false', [])
        self.assert_query(provider, 'true and true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'true and NULL', [])
        self.assert_query(provider, 'NULL and false', [])
        self.assert_query(provider, 'NULL and true', [])
        self.assert_query(provider, 'NULL and NULL', [])
        self.assert_query(provider, 'false or false', [])
        self.assert_query(provider, 'false or true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'false or NULL', [])
        self.assert_query(provider, 'true or false', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'true or true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'true or NULL', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'NULL or false', [])
        self.assert_query(provider, 'NULL or true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'NULL or NULL', [])
        self.assert_query(provider, 'not true', [])
        self.assert_query(provider, 'not false', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'not null', [])

        # not
        self.assert_query(provider, 'not name = \'Apple\'', [1, 3, 4])
        self.assert_query(provider, 'not name IS NULL', [1, 2, 3, 4])
        self.assert_query(provider, 'not name = \'Apple\' or name = \'Apple\'',
                          [1, 2, 3, 4])
        self.assert_query(provider,
                          'not name = \'Apple\' or not name = \'Apple\'',
                          [1, 3, 4])
        self.assert_query(provider, 'not name = \'Apple\' and pk = 4', [4])
        self.assert_query(provider, 'not name = \'Apple\' and not pk = 4',
                          [1, 3])
        self.assert_query(provider, 'not pk IN (1, 2, 4, 8)', [3, 5])

        # type conversion - QGIS expressions do not mind that we are comparing a string
        # against numeric literals
        self.assert_query(provider, 'num_char IN (2, 4, 5)', [2, 4, 5])

        # geometry
        self.assert_query(
            provider,
            'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))',
            [1, 2])

        # combination of an uncompilable expression and limit
        feature = next(self.vl.getFeatures('pk=4'))
        context = QgsExpressionContext()
        scope = QgsExpressionContextScope()
        scope.setVariable('parent', feature)
        context.appendScope(scope)

        request = QgsFeatureRequest()
        request.setExpressionContext(context)
        request.setFilterExpression('"pk" = attribute(@parent, \'pk\')')
        request.setLimit(1)

        values = [f['pk'] for f in self.vl.getFeatures(request)]
        self.assertEqual(values, [4])
Example #31
0
    def runGetFeatureTests(self, provider):
        assert len([f for f in provider.getFeatures()]) == 5
        self.assert_query(provider, 'name ILIKE \'QGIS\'', [])
        self.assert_query(provider, '"name" IS NULL', [5])
        self.assert_query(provider, '"name" IS NOT NULL', [1, 2, 3, 4])
        self.assert_query(provider, '"name" NOT LIKE \'Ap%\'', [1, 3, 4])
        self.assert_query(provider, '"name" NOT ILIKE \'QGIS\'', [1, 2, 3, 4])
        self.assert_query(provider, '"name" NOT ILIKE \'pEAR\'', [1, 2, 4])
        self.assert_query(provider, 'name = \'Apple\'', [2])
        self.assert_query(provider, 'name <> \'Apple\'', [1, 3, 4])
        self.assert_query(provider, 'name = \'apple\'', [])
        self.assert_query(provider, '"name" <> \'apple\'', [1, 2, 3, 4])
        self.assert_query(provider, '(name = \'Apple\') is not null', [1, 2, 3, 4])
        self.assert_query(provider, 'name LIKE \'Apple\'', [2])
        self.assert_query(provider, 'name LIKE \'aPple\'', [])
        self.assert_query(provider, 'name ILIKE \'aPple\'', [2])
        self.assert_query(provider, 'name ILIKE \'%pp%\'', [2])
        self.assert_query(provider, 'cnt > 0', [1, 2, 3, 4])
        self.assert_query(provider, '-cnt > 0', [5])
        self.assert_query(provider, 'cnt < 0', [5])
        self.assert_query(provider, '-cnt < 0', [1, 2, 3, 4])
        self.assert_query(provider, 'cnt >= 100', [1, 2, 3, 4])
        self.assert_query(provider, 'cnt <= 100', [1, 5])
        self.assert_query(provider, 'pk IN (1, 2, 4, 8)', [1, 2, 4])
        self.assert_query(provider, 'cnt = 50 * 2', [1])
        self.assert_query(provider, 'cnt = 99 + 1', [1])
        self.assert_query(provider, 'cnt = 101 - 1', [1])
        self.assert_query(provider, 'cnt - 1 = 99', [1])
        self.assert_query(provider, '-cnt - 1 = -101', [1])
        self.assert_query(provider, '-(-cnt) = 100', [1])
        self.assert_query(provider, '-(cnt) = -(100)', [1])
        self.assert_query(provider, 'cnt + 1 = 101', [1])
        self.assert_query(provider, 'cnt = 1100 % 1000', [1])
        self.assert_query(provider, '"name" || \' \' || "name" = \'Orange Orange\'', [1])
        self.assert_query(provider, '"name" || \' \' || "cnt" = \'Orange 100\'', [1])
        self.assert_query(provider, '\'x\' || "name" IS NOT NULL', [1, 2, 3, 4])
        self.assert_query(provider, '\'x\' || "name" IS NULL', [5])
        self.assert_query(provider, 'cnt = 10 ^ 2', [1])
        self.assert_query(provider, '"name" ~ \'[OP]ra[gne]+\'', [1])
        self.assert_query(provider, '"name"="name2"', [2, 4])  # mix of matched and non-matched case sensitive names
        self.assert_query(provider, 'true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'false', [])

        # Three value logic
        self.assert_query(provider, 'false and false', [])
        self.assert_query(provider, 'false and true', [])
        self.assert_query(provider, 'false and NULL', [])
        self.assert_query(provider, 'true and false', [])
        self.assert_query(provider, 'true and true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'true and NULL', [])
        self.assert_query(provider, 'NULL and false', [])
        self.assert_query(provider, 'NULL and true', [])
        self.assert_query(provider, 'NULL and NULL', [])
        self.assert_query(provider, 'false or false', [])
        self.assert_query(provider, 'false or true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'false or NULL', [])
        self.assert_query(provider, 'true or false', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'true or true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'true or NULL', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'NULL or false', [])
        self.assert_query(provider, 'NULL or true', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'NULL or NULL', [])
        self.assert_query(provider, 'not true', [])
        self.assert_query(provider, 'not false', [1, 2, 3, 4, 5])
        self.assert_query(provider, 'not null', [])

        # not
        self.assert_query(provider, 'not name = \'Apple\'', [1, 3, 4])
        self.assert_query(provider, 'not name IS NULL', [1, 2, 3, 4])
        self.assert_query(provider, 'not name = \'Apple\' or name = \'Apple\'', [1, 2, 3, 4])
        self.assert_query(provider, 'not name = \'Apple\' or not name = \'Apple\'', [1, 3, 4])
        self.assert_query(provider, 'not name = \'Apple\' and pk = 4', [4])
        self.assert_query(provider, 'not name = \'Apple\' and not pk = 4', [1, 3])
        self.assert_query(provider, 'not pk IN (1, 2, 4, 8)', [3, 5])

        # type conversion - QGIS expressions do not mind that we are comparing a string
        # against numeric literals
        self.assert_query(provider, 'num_char IN (2, 4, 5)', [2, 4, 5])

        # geometry
        self.assert_query(provider, 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', [1, 2])

        # combination of an uncompilable expression and limit
        feature = next(self.vl.getFeatures('pk=4'))
        context = QgsExpressionContext()
        scope = QgsExpressionContextScope()
        scope.setVariable('parent', feature)
        context.appendScope(scope)

        request = QgsFeatureRequest()
        request.setExpressionContext(context)
        request.setFilterExpression('"pk" = attribute(@parent, \'pk\')')
        request.setLimit(1)

        values = [f['pk'] for f in self.vl.getFeatures(request)]
        self.assertEqual(values, [4])
Example #32
0
 def testLimit(self):
     req = QgsFeatureRequest()
     self.assertEqual(req.limit(), -1)
     req.setLimit(6)
     self.assertEqual(req.limit(), 6)
Example #33
0
    def responseComplete(self):
        """
        Send new response
        """
        self.handler = self.serverIface.requestHandler()
        params = self.handler.parameterMap()

        # Check if needed params are passed
        # If not, do not change QGIS Server response
        service = params.get('SERVICE')
        if not service:
            return

        if service.lower() != 'wms':
            return

        # Check if getprintatlas request. If not, just send the response
        if 'REQUEST' not in params or params['REQUEST'].lower() not in ['getprintatlas', 'getcapabilitiesatlas']:
            return

        # Get capabilities
        if params['REQUEST'].lower() == 'getcapabilitiesatlas':
            body = {
                'status': 'success',
                'metadata': self.metadata
            }
            self.setJsonResponse('200', body)
            return

        # Check if needed params are set
        required = ['TEMPLATE', 'EXP_FILTER']
        if not all(elem in params for elem in required):
            body = {
                'status': 'fail',
                'message': 'Missing parameters: {} are required.'.format(' '.join(required))
            }
            self.setJsonResponse('400', body)
            return

        self.project_path = self.serverInterface().configFilePath()
        self.composer_name = params['TEMPLATE']
        self.feature_filter = params['EXP_FILTER']

        # check expression
        expression = QgsExpression(self.feature_filter)
        if not expression.hasParserError():
            feature_request = QgsFeatureRequest(expression)
            feature_request.setLimit(1)
        else:
            body = {
                'status': 'fail',
                'message': 'An error occurred while parsing the given expression: %s' % expression.parserErrorString()
            }
            QgsMessageLog.logMessage('ATLAS - ERROR EXPRESSION: {}'.format(expression.parserErrorString()), 'atlasprint', Qgis.Critical)
            self.setJsonResponse('400', body)
            return

        # noinspection PyBroadException
        try:
            pdf = self.print_atlas(
                project_path=self.project_path,
                composer_name=self.composer_name,
                predefined_scales=self.predefined_scales,
                feature_filter=self.feature_filter
            )
        except Exception:
            pdf = None

        if not pdf:
            body = {
                'status': 'fail',
                'message': 'ATLAS - Error while generating the PDF'
            }
            QgsMessageLog.logMessage("ATLAS - No PDF generated in %s" % pdf, 'atlasprint', Qgis.Critical)
            self.setJsonResponse('500', body)
            return

        # Send PDF
        self.handler.clear()
        self.handler.setResponseHeader('Content-type', 'application/pdf')
        self.handler.setResponseHeader('Status', '200')

        # noinspection PyBroadException
        try:
            with open(pdf, 'rb') as f:
                loads = f.readlines()
                ba = QByteArray(b''.join(loads))
                self.handler.appendBody(ba)
        except Exception:
            body = {
                'status': 'fail',
                'message': 'Error occured while reading PDF file',
            }
            self.setJsonResponse('500', body)
        finally:
            os.remove(pdf)

        return
Example #34
0
    def processAlgorithm(self, parameters, context, feedback):

        t_regard = self.parameterAsSource(parameters, self.MANHOLES_TABLE,
                                          context)
        g_regard = self.parameterAsSource(parameters, self.GEOM_MANHOLES,
                                          context)
        t_troncon = self.parameterAsVectorLayer(parameters,
                                                self.SEGMENTS_TABLE, context)
        g_troncon = self.parameterAsVectorLayer(parameters, self.GEOM_SEGMENTS,
                                                context)

        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(
            QgsExpressionContextUtils.projectScope(context.project()))
        exp_context.appendScope(
            QgsExpressionContextUtils.layerScope(t_troncon))

        exp_str = '"id_geom_troncon" IS NULL'
        exp = QgsExpression(exp_str)

        exp.prepare(exp_context)
        if exp.hasEvalError():
            raise QgsProcessingException(
                tr('* ERROR: Expression {} has eval error: {}').format(
                    exp.expression(), exp.evalErrorString()))

        request = QgsFeatureRequest(exp, exp_context)
        r_ids = []  # identifiant des regards
        l_t_f = {}  # lien troncon fichier
        l_f_t = {}  # lien fichier troncons
        troncons = {}
        sorties = {}
        entrees = {}
        for tro in t_troncon.getFeatures(request):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SEGMENT_CREATED: None}

            segment_number = tro['id']
            r1 = tro['id_regard1']
            r2 = tro['id_regard2']

            if r1 not in r_ids:
                r_ids.append(r1)
            if r2 not in r_ids:
                r_ids.append(r2)

            fid = tro['id_file']
            l_t_f[segment_number] = fid
            if fid in l_f_t:
                l_f_t[fid] = l_f_t[fid] + [segment_number]
            else:
                l_f_t[fid] = [segment_number]

            troncons[segment_number] = (r1, r2)
            if r1 in sorties:
                sorties[r1] = sorties[r1] + [segment_number]
            else:
                sorties[r1] = [segment_number]
            if r2 in entrees:
                entrees[r2] = entrees[r2] + [segment_number]
            else:
                entrees[r2] = [segment_number]

        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(
            QgsExpressionContextUtils.projectScope(context.project()))
        exp_context.appendScope(t_regard.createExpressionContextScope())

        exp_str = ('"id_geom_regard" IS NOT NULL '
                   'AND '
                   '"id" IN ({})').format(','.join([str(i)
                                                    for i in r_ids] + ['-1']))
        exp = QgsExpression(exp_str)

        exp.prepare(exp_context)
        if exp.hasEvalError():
            raise QgsProcessingException(
                tr('* ERROR: Expression {} has eval error: {}').format(
                    exp.expression(), exp.evalErrorString()))

        request = QgsFeatureRequest(exp, exp_context)
        g_ids = []  # identifiants des géométrie de regards
        l_r_g = {}  # lien regard geometrie
        l_g_r = {}  # lien geometrie regards
        for reg in t_regard.getFeatures(request):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SEGMENT_CREATED: None}

            segment_number = reg['id']
            fid = reg['id_file']

            if segment_number in sorties:
                sorties[segment_number] = [
                    trid for trid in sorties[segment_number]
                    if l_t_f[trid] == fid
                ]
            if segment_number in entrees:
                entrees[segment_number] = [
                    trid for trid in entrees[segment_number]
                    if l_t_f[trid] == fid
                ]

            gid = reg['id_geom_regard']
            l_r_g[segment_number] = gid
            if gid not in g_ids:
                g_ids.append(gid)
            if gid in l_g_r:
                l_g_r[gid] = l_g_r[gid] + [segment_number]
            else:
                l_g_r[gid] = [segment_number]

        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(
            QgsExpressionContextUtils.projectScope(context.project()))
        exp_context.appendScope(g_regard.createExpressionContextScope())

        exp_str = '"id" IN ({})'.format(','.join([str(i)
                                                  for i in g_ids] + ['-1']))
        exp = QgsExpression(exp_str)

        exp.prepare(exp_context)
        if exp.hasEvalError():
            raise QgsProcessingException(
                tr('* ERROR: Expression {} has eval error: {}').format(
                    exp.expression(), exp.evalErrorString()))

        request = QgsFeatureRequest(exp, exp_context)
        points = {}
        pt_labels = {}
        for reg in g_regard.getFeatures(request):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SEGMENT_CREATED: None}

            segment_number = reg['id']
            points[segment_number] = reg.geometry().asPoint()
            pt_labels[segment_number] = reg['label']

        lines = {}
        for gid in points:
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SEGMENT_CREATED: None}

            if gid not in l_g_r:
                continue

            for rid in l_g_r[gid]:
                # Stop the algorithm if cancel button has been clicked
                if feedback.isCanceled():
                    return {self.SEGMENT_CREATED: None}

                if rid in sorties:
                    for tid in sorties[rid]:
                        # Stop the algorithm if cancel button has been clicked
                        if feedback.isCanceled():
                            return {self.SEGMENT_CREATED: None}

                        if tid in lines:
                            continue
                        if tid not in troncons:
                            continue
                        r2 = troncons[tid][1]
                        if r2 not in l_r_g:
                            continue
                        g2 = l_r_g[r2]
                        if g2 not in points:
                            continue
                        lines[tid] = (gid, g2)

                if rid in entrees:
                    for tid in entrees[rid]:
                        # Stop the algorithm if cancel button has been clicked
                        if feedback.isCanceled():
                            return {self.SEGMENT_CREATED: None}

                        if tid in lines:
                            continue
                        if tid not in troncons:
                            continue
                        r1 = troncons[tid][0]
                        if r1 not in l_r_g:
                            continue
                        g1 = l_r_g[r1]
                        if g1 not in points:
                            continue
                        lines[tid] = (g1, gid)

        # Creation des troncons
        l_t_g = {}  # lien troncon et geometrie troncon
        l_pts_t = {}  # lien points troncons
        features = []  # les objets de geometrie de troncon
        geom_point_keys = []  # liste des clés des points troncons
        for tid, pts in lines.items():
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SEGMENT_CREATED: None}

            exp_context = QgsExpressionContext()
            exp_context.appendScope(QgsExpressionContextUtils.globalScope())
            exp_context.appendScope(
                QgsExpressionContextUtils.projectScope(context.project()))
            exp_context.appendScope(
                QgsExpressionContextUtils.layerScope(g_troncon))

            exp_str = ('"id_geom_regard_amont" = {} AND '
                       '"id_geom_regard_aval" = {}').format(pts[0], pts[1])
            exp = QgsExpression(exp_str)

            exp.prepare(exp_context)
            if exp.hasEvalError():
                raise QgsProcessingException(
                    tr('* ERROR: Expression {} has eval error: {}').format(
                        exp.expression(), exp.evalErrorString()))

            request = QgsFeatureRequest(exp, exp_context)
            request.setLimit(1)
            for tro in g_troncon.getFeatures(request):
                l_t_g[tid] = tro['id']
                continue

            if (pts[0], pts[1]) in geom_point_keys:
                l_pts_t[(pts[0], pts[1])].append(tid)
                continue
            else:
                l_pts_t[(pts[0], pts[1])] = [tid]
                geom_point_keys.append((pts[0], pts[1]))

            feat_t = QgsVectorLayerUtils.createFeature(g_troncon)
            feat_t.setAttribute(
                'label', '{}-{}'.format(pt_labels[pts[0]], pt_labels[pts[1]]))
            feat_t.setAttribute('id_geom_regard_amont', pts[0])
            feat_t.setAttribute('id_geom_regard_aval', pts[1])
            feat_t.setGeometry(
                QgsGeometry.fromPolylineXY([points[pts[0]], points[pts[1]]]))
            features.append(feat_t)

        # Ajout des objets troncons
        if features:
            g_troncon.startEditing()
            (res, outFeats) = g_troncon.dataProvider().addFeatures(features)
            if not res or not outFeats:
                raise QgsProcessingException(
                    tr('* ERREUR: lors de l\'enregistrement '
                       'des regards {}').format(', '.join(
                           g_troncon.dataProvider().errors())))
            if not g_troncon.commitChanges():
                raise QgsProcessingException(
                    tr('* ERROR: Commit {}.').format(g_troncon.commitErrors()))

            for tro in outFeats:
                # Stop the algorithm if cancel button has been clicked
                if feedback.isCanceled():
                    return {self.SEGMENT_CREATED: None}

                if not tro['id']:
                    continue
                key = (tro['id_geom_regard_amont'], tro['id_geom_regard_aval'])
                if key not in geom_point_keys:
                    continue
                for tid in l_pts_t[(pts[0], pts[1])]:
                    l_t_g[tid] = tro['id']
                    # Stop the algorithm if cancel button has been clicked
                    if feedback.isCanceled():
                        return {self.SEGMENT_CREATED: None}

        for tid, pts in lines.items():
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SEGMENT_CREATED: None}

            if tid in l_t_g:
                continue
            exp_context = QgsExpressionContext()
            exp_context.appendScope(QgsExpressionContextUtils.globalScope())
            exp_context.appendScope(
                QgsExpressionContextUtils.projectScope(context.project()))
            exp_context.appendScope(
                QgsExpressionContextUtils.layerScope(g_troncon))

            exp_str = ('"id_geom_regard_amont" = {} AND '
                       '"id_geom_regard_aval" = {}').format(pts[0], pts[1])
            exp = QgsExpression(exp_str)

            exp.prepare(exp_context)
            if exp.hasEvalError():
                raise QgsProcessingException(
                    tr('* ERROR: Expression {} has eval error: {}').format(
                        exp.expression(), exp.evalErrorString()))

            request = QgsFeatureRequest(exp, exp_context)
            request.setLimit(1)
            for tro in g_troncon.getFeatures(request):
                l_t_g[tid] = tro['id']
                # Stop the algorithm if cancel button has been clicked
                if feedback.isCanceled():
                    return {self.SEGMENT_CREATED: None}

        if not l_t_g.keys():
            raise QgsProcessingException(
                tr('* ERREUR: Aucune géométrie de tronçon'))

        # Mise a jour de la table troncon
        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(
            QgsExpressionContextUtils.projectScope(context.project()))
        exp_context.appendScope(
            QgsExpressionContextUtils.layerScope(t_troncon))

        exp_str = ('"id_geom_troncon" IS NULL AND '
                   'id IN ({})').format(','.join(
                       [str(i) for i in l_t_g.keys()]))
        exp = QgsExpression(exp_str)

        exp.prepare(exp_context)
        if exp.hasEvalError():
            raise QgsProcessingException(
                tr('* ERROR: Expression %s has eval error: %s').format(
                    exp.expression(), exp.evalErrorString()))

        # Mise a jour de la table de tronçon
        request = QgsFeatureRequest(exp, exp_context)
        t_troncon.startEditing()
        segment_number = 0
        for tro in t_troncon.getFeatures(request):
            tro.setAttribute('id_geom_troncon', l_t_g[tro['id']])
            t_troncon.updateFeature(tro)
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.SEGMENT_CREATED: None}
            segment_number += 1

        if not t_troncon.commitChanges():
            raise QgsProcessingException(
                tr('* ERROR: Commit %s.') % t_troncon.commitErrors())

        # Returns empty dict if no outputs
        return {self.SEGMENT_CREATED: segment_number}