Example #1
0
    def _pre_search_validation(self, location, query, sort_by,
                               return_fields, max_features):
        """Perform validation on the parameters of the search query.

        Parameters
        ----------
        location : pydov.util.location.AbstractLocationFilter
            Location filter limiting the features to retrieve.
        query : owslib.fes.OgcExpression
            OGC filter expression to use for searching. This can contain any
            combination of filter elements defined in owslib.fes. The query
            should use the fields provided in `get_fields()`. Note that not
            all fields are currently supported as a search parameter.
        sort_by : owslib.fes.SortBy, optional
            List of properties to sort by.
        return_fields : list<str> or tuple<str> or set<str>
            A list of fields to be returned in the output data. This should
            be a subset of the fields provided in `get_fields()`.
        max_features : int
            Limit the maximum number of features to request.

        Raises
        ------
        pydov.util.errors.InvalidSearchParameterError
            When not one of `location`, `query` or `max_features` is provided.

        pydov.util.errors.InvalidFieldError
            When at least one of the fields in `return_fields` is unknown.

            When a field that is only accessible as return field is used as
            a query parameter.

        """
        if location is None and query is None and max_features is None:
            raise InvalidSearchParameterError(
                'Provide either the location or the query parameter or the '
                'max_features parameter.'
            )

        if query is not None:
            if not isinstance(query, owslib.fes.OgcExpression):
                raise InvalidSearchParameterError(
                    "Query should be an owslib.fes.OgcExpression.")

            filter_request = FilterRequest()
            filter_request = filter_request.setConstraint(query)

            self._init_fields()
            for property_name in filter_request.findall(
                    './/{http://www.opengis.net/ogc}PropertyName'):
                name = property_name.text
                if name not in self._map_df_wfs_source \
                        and name not in self._wfs_fields:
                    if name in self._fields:
                        raise InvalidFieldError(
                            "Cannot use return field '{}' in query.".format(
                                name))
                    raise InvalidFieldError(
                        "Unknown query parameter: '{}'".format(name))

        if location is not None:
            self._init_fields()

        if sort_by is not None:
            if not isinstance(sort_by, owslib.fes.SortBy):
                raise InvalidSearchParameterError(
                    "SortBy should be an owslib.fes.SortBy")

            self._init_fields()
            for property_name in sort_by.toXML().findall(
                    './/{http://www.opengis.net/ogc}PropertyName'):
                name = property_name.text
                if name not in self._map_df_wfs_source \
                        and name not in self._wfs_fields:
                    if name in self._fields:
                        raise InvalidFieldError(
                            "Cannot use return field '{}' for sorting.".format(
                                name))
                    raise InvalidFieldError(
                        "Unknown query parameter: '{}'".format(name))

        if return_fields is not None:
            if type(return_fields) not in (list, tuple, set):
                raise AttributeError('return_fields should be a list, '
                                     'tuple or set')

            self._init_fields()
            for rf in return_fields:
                if rf not in self._fields:
                    if rf in self._map_wfs_source_df:
                        raise InvalidFieldError(
                            "Unknown return field: "
                            "'{}'. Did you mean '{}'?".format(
                                rf, self._map_wfs_source_df[rf]))
                    if rf.lower() in [i.lower() for i in
                                      self._map_wfs_source_df.keys()]:
                        sugg = [i for i in self._map_wfs_source_df.keys() if
                                i.lower() == rf.lower()][0]
                        raise InvalidFieldError(
                            "Unknown return field: "
                            "'{}'. Did you mean '{}'?".format(rf, sugg))
                    raise InvalidFieldError(
                        "Unknown return field: '{}'".format(rf))
Example #2
0
    def _search(self, location=None, query=None, return_fields=None,
                sort_by=None, max_features=None, extra_wfs_fields=[]):
        """Perform the WFS search by issuing a GetFeature request.

        Parameters
        ----------
        location : pydov.util.location.AbstractLocationFilter
            Location filter limiting the features to retrieve.
        query : owslib.fes.OgcExpression
            OGC filter expression to use for searching. This can contain any
            combination of filter elements defined in owslib.fes. The query
            should use the fields provided in `get_fields()`. Note that not
            all fields are currently supported as a search parameter.
        return_fields : list<str>
            A list of fields to be returned in the output data. This should
            be a subset of the fields provided in `get_fields()`. Note that
            not all fields are currently supported as return fields.
        sort_by : owslib.fes.SortBy, optional
            List of properties to sort by.
        max_features : int
            Limit the maximum number of features to request.
        extra_wfs_fields: list<str>
            A list of extra fields to be included in the WFS requests,
            regardless whether they're needed as return field. Optional,
            defaults to an empty list.

        Returns
        -------
        etree.Element
            XML tree of the WFS response containing the features matching
            the location or the query.

        Raises
        ------
        pydov.util.errors.InvalidSearchParameterError
            When not one of `location`, `query` or `max_features` is provided.

        pydov.util.errors.InvalidFieldError
            When at least one of the fields in `return_fields` is unknown.

            When a field that is only accessible as return field is used as
            a query parameter.

            When a field that can only be used as a query parameter is used as
            a return field.

        pydov.util.errors.FeatureOverflowError
            When the number of features to be returned is equal to the
            maxFeatures limit of the WFS server.

        """
        self._pre_search_validation(location, query, sort_by, return_fields,
                                    max_features)
        self._init_namespace()
        self._init_wfs()

        filter_request = None
        if query is not None:
            filter_request = FilterRequest()
            filter_request = filter_request.setConstraint(query)

        if filter_request is not None:
            for property_name in filter_request.findall(
                    './/{http://www.opengis.net/ogc}PropertyName'):
                property_name.text = self._map_df_wfs_source.get(
                    property_name.text, property_name.text)

            try:
                filter_request = etree.tostring(filter_request,
                                                encoding='unicode')
            except LookupError:
                # Python2.7 without lxml uses 'utf-8' instead.
                filter_request = etree.tostring(filter_request,
                                                encoding='utf-8')

        if return_fields is None:
            wfs_property_names = [
                f['sourcefield'] for f in self._type.get_fields(
                    source=('wfs',)).values() if not f.get(
                    'wfs_injected', False)]
        else:
            wfs_property_names = [self._map_df_wfs_source[i]
                                  for i in self._map_df_wfs_source
                                  if i.startswith('pkey')]
            wfs_property_names.extend([self._map_df_wfs_source[i]
                                       for i in self._map_df_wfs_source
                                       if i in return_fields])

        wfs_property_names.extend(extra_wfs_fields)
        wfs_property_names = list(set(wfs_property_names))

        if sort_by is not None:
            sort_by_xml = sort_by.toXML()
            for property_name in sort_by_xml.findall(
                    './/{http://www.opengis.net/ogc}PropertyName'):
                property_name.text = self._map_df_wfs_source.get(
                    property_name.text, property_name.text)

            try:
                sort_by = etree.tostring(sort_by_xml, encoding='unicode')
            except LookupError:
                # Python2.7 without lxml uses 'utf-8' instead.
                sort_by = etree.tostring(sort_by_xml, encoding='utf-8')

        fts = self._get_remote_wfs_feature(
            wfs=self.__wfs,
            typename=self._layer,
            location=location,
            filter=filter_request,
            sort_by=sort_by,
            max_features=max_features,
            propertyname=wfs_property_names,
            geometry_column=self._geometry_column)

        tree = etree.fromstring(fts)

        if tree.get('numberOfFeatures') is None:
            raise WfsGetFeatureError(
                'Error retrieving features from DOV WFS server:\n{}'.format(
                    etree.tostring(tree).decode('utf8')))

        if int(tree.get('numberOfFeatures')) == 10000:
            raise FeatureOverflowError(
                'Reached the limit of {:d} returned features. Please split up '
                'the query to ensure getting all results.'.format(10000))

        for hook in pydov.hooks:
            hook.wfs_search_result(int(tree.get('numberOfFeatures')))

        return tree
Example #3
0
    def _pre_search_validation(self,
                               location=None,
                               query=None,
                               return_fields=None):
        """Perform validation on the parameters of the search query.

        Parameters
        ----------
        location : tuple<minx,miny,maxx,maxy>
            The bounding box limiting the features to retrieve.
        query : owslib.fes.OgcExpression
            OGC filter expression to use for searching. This can contain any
            combination of filter elements defined in owslib.fes. The query
            should use the fields provided in `get_fields()`. Note that not
            all fields are currently supported as a search parameter.
        return_fields : list<str> or tuple<str> or set<str>
            A list of fields to be returned in the output data. This should
            be a subset of the fields provided in `get_fields()`.

        Raises
        ------
        pydov.util.errors.InvalidSearchParameterError
            When not one of `location` or `query` is provided.

        pydov.util.errors.InvalidFieldError
            When at least one of the fields in `return_fields` is unknown.

            When a field that is only accessible as return field is used as
            a query parameter.

        """
        if location is None and query is None:
            raise InvalidSearchParameterError(
                'Provide either the location or the query parameter.')

        if query is not None:
            if not isinstance(query, owslib.fes.OgcExpression):
                raise InvalidSearchParameterError(
                    "Query should be an owslib.fes.OgcExpression.")

            filter_request = FilterRequest()
            filter_request = filter_request.setConstraint(query)

            self._init_fields()
            for property_name in filter_request.findall(
                    './/{http://www.opengis.net/ogc}PropertyName'):
                name = property_name.text
                if name not in self._map_df_wfs_source \
                        and name not in self._wfs_fields:
                    if name in self._fields:
                        raise InvalidFieldError(
                            "Cannot use return field '%s' in query." % name)
                    raise InvalidFieldError("Unknown query parameter: '%s'" %
                                            name)

        if location is not None:
            self._init_fields()

        if return_fields is not None:
            if type(return_fields) not in (list, tuple, set):
                raise AttributeError('return_fields should be a list, '
                                     'tuple or set')

            self._init_fields()
            for rf in return_fields:
                if rf not in self._fields:
                    if rf in self._map_wfs_source_df:
                        raise InvalidFieldError(
                            "Unknown return field: '%s'. Did you mean '%s'?" %
                            (rf, self._map_wfs_source_df[rf]))
                    if rf.lower() in [
                            i.lower() for i in self._map_wfs_source_df.keys()
                    ]:
                        sugg = [
                            i for i in self._map_wfs_source_df.keys()
                            if i.lower() == rf.lower()
                        ][0]
                        raise InvalidFieldError(
                            "Unknown return field: '%s'. Did you mean '%s'?" %
                            (rf, sugg))
                    raise InvalidFieldError("Unknown return field: '%s'" % rf)