def get_pagination_info(arguments): """Get pagination arguments""" page = get_int(arguments.pop("page", DEFAULT_PAGE)) # items_per_page can be specified using limit or itemsPerPage items_per_page = get_int(arguments.pop("limit", DEFAULT_ITEMS_PER_PAGE)) items_per_page = get_int(arguments.pop("itemsPerPage", items_per_page)) if page is not None and page < 0: raise ValidationError("invalid page number. Must be positive integer") if items_per_page is not None and items_per_page < 0: raise ValidationError( "invalid number of items per page. Must be positive integer") return page, items_per_page
def validate(config_keys): """Validate a :class:`~eodag.config.ProviderConfig`""" if "name" not in config_keys: raise ValidationError("Provider config must have name key") if not any(k in config_keys for k in ("api", "search", "download", "auth")): raise ValidationError("A provider must implement at least one plugin") if "api" in config_keys and any( k in config_keys for k in ("search", "download", "auth") ): raise ValidationError( "A provider implementing an Api plugin must not implement any other " "type of plugin" )
def get_geometry(arguments): """Get geometry from arguments """ geom = None if "bbox" in arguments or "box" in arguments: # get bbox request_bbox = arguments.pop("bbox", None) or arguments.pop( "box", None) if request_bbox and isinstance(request_bbox, str): request_bbox = request_bbox.split(",") elif request_bbox and not isinstance(request_bbox, list): raise ValidationError("bbox argument type should be Array") try: request_bbox_list = [float(coord) for coord in request_bbox] except ValueError as e: raise ValidationError("invalid bbox coordinate type: %s" % e) # lonmin, latmin, lonmax, latmax if len(request_bbox_list) < 4: raise ValidationError("invalid bbox length (%s) for bbox %s" % (len(request_bbox_list), request_bbox)) geom = Polygon(( (request_bbox_list[0], request_bbox_list[1]), (request_bbox_list[0], request_bbox_list[3]), (request_bbox_list[2], request_bbox_list[3]), (request_bbox_list[2], request_bbox_list[1]), )) if "intersects" in arguments and geom: new_geom = shape(arguments.pop("intersects")) if new_geom.intersects(geom): geom = new_geom.intersection(geom) else: geom = new_geom elif "intersects" in arguments: geom = shape(arguments.pop("intersects")) if "geom" in arguments and geom: new_geom = shape(arguments.pop("geom")) if new_geom.intersects(geom): geom = new_geom.intersection(geom) else: geom = new_geom elif "geom" in arguments: geom = shape(arguments.pop("geom")) return geom
def get_int(val): """Check if the input can be parsed as an integer""" if val: try: val = int(val) except ValueError as e: raise ValidationError("invalid input integer value: %s" % e) return val
def get_date(date): """Check if the input date can be parsed as a date""" if date: try: date = (dateutil.parser.parse(date).replace( tzinfo=tz.UTC).isoformat().replace("+00:00", "")) except ValueError as e: exc = ValidationError("invalid input date: %s" % e) raise exc return date
def search_bbox(request_bbox): """Transform request bounding box as a bbox suitable for eodag search""" eodag_bbox = None search_bbox_keys = ["lonmin", "latmin", "lonmax", "latmax"] if request_bbox: try: request_bbox_list = [ float(coord) for coord in request_bbox.split(",") ] except ValueError as e: raise ValidationError("invalid box coordinate type: %s" % e) eodag_bbox = dict(zip(search_bbox_keys, request_bbox_list)) if len(eodag_bbox) != 4: raise ValidationError("input box is invalid: %s" % request_bbox) return eodag_bbox
def filter_products(products, arguments, **kwargs): """Apply an eodag cruncher to filter products""" filter_name = arguments.get("filter") if filter_name: cruncher = crunchers.get(filter_name) if not cruncher: raise ValidationError("unknown filter name") cruncher_config = dict() for config_param in cruncher.config_params: config_param_value = arguments.get(config_param) if not config_param_value: raise ValidationError( "filter additional parameters required: %s" % ", ".join(cruncher.config_params)) cruncher_config[config_param] = config_param_value try: products = products.crunch(cruncher.clazz(cruncher_config), **kwargs) except MisconfiguredError as e: raise ValidationError(e) return products
def validate(config_keys): """Validate a :class:`~eodag.config.PluginConfig`""" if "type" not in config_keys: raise ValidationError( "A Plugin config must specify the Plugin it configures" )
def __build_stac_catalog(self, catalogs=[]): """Build nested catalog from catalag list :param catalogs: catalogs list :type catalogs: list :returns: this catalog obj :rtype: :class:`eodag.stac.StacCatalog` """ # update conf with user shp locations locations_config = self.build_locations_config() self.stac_config["catalogs"] = dict( copy.deepcopy(self.stac_config["catalogs"]), **locations_config) if len(catalogs) == 0: # Build root catalog combined with landing page self.__update_data_from_catalog_config( { "model": dict( copy.deepcopy(self.stac_config["landing_page"]), **{"provider": self.provider}, ) } # {"model": copy.deepcopy(self.stac_config["landing_page"])} ) # build children : product_types product_types_list = [ pt for pt in self.eodag_api.list_product_types( provider=self.provider) if pt["ID"] != GENERIC_PRODUCT_TYPE ] self.set_children([{ "rel": "child", "href": self.url + "/" + product_type["ID"], "title": product_type["ID"], } for product_type in product_types_list]) else: # use product_types_list as base for building nested catalogs self.__update_data_from_catalog_config( copy.deepcopy( self.stac_config["catalogs"]["product_types_list"])) for idx, cat in enumerate(catalogs): if idx % 2 == 0: # even: cat is a filtering value ---------------------------------- cat_data_name = self.catalog_config["child_key"] cat_data_value = cat # update data set_data_method_name = ( "set_stac_%s_by_id" % cat_data_name if "catalog_type" not in self.stac_config["catalogs"][cat_data_name].keys() else "set_stac_%s_by_id" % self.stac_config["catalogs"][cat_data_name]["catalog_type"] ) set_data_method = getattr(self, set_data_method_name) set_data_method(cat_data_value, catalog_name=cat_data_name) if idx == len(catalogs) - 1: # build children : remaining filtering keys remaining_catalogs_list = [ c for c in self.stac_config["catalogs"].keys() # keep filters not used yet AND if self.stac_config["catalogs"][c]["model"]["id"] not in catalogs and ( # filters with no parent_key constraint (no key, or key=None) OR "parent_key" not in self.stac_config["catalogs"][c] or not self.stac_config["catalogs"][c]["parent_key"] # filters matching parent_key constraint or self.stac_config["catalogs"][c]["parent_key"] == cat_data_name) # AND filters that match parent attr constraint (locations) and ("parent" not in self.stac_config["catalogs"][c] or not self.stac_config["catalogs"][c]["parent"]["key"] or (self.stac_config["catalogs"][c]["parent"]["key"] == cat_data_name and self.stac_config["catalogs"] [c]["parent"]["attr"] == cat_data_value)) ] self.set_children([{ "rel": "child", "href": self.url + "/" + self.stac_config["catalogs"][c]["model"]["id"], "title": str(self.stac_config["catalogs"][c]["model"]["id"]), } for c in remaining_catalogs_list] + [{ "rel": "items", "href": self.url + "/items", "title": "items", }]) else: # odd: cat is a filtering key ------------------------------------- try: cat_key = [ c for c in self.stac_config["catalogs"].keys() if self.stac_config["catalogs"][c]["model"]["id"] == cat ][0] except IndexError: raise ValidationError( "Bad settings for %s in stac_config catalogs" % cat) cat_config = copy.deepcopy( self.stac_config["catalogs"][cat_key]) # update data self.__update_data_from_catalog_config(cat_config) # get filtering values list get_data_method_name = ( "get_stac_%s" % cat_key if "catalog_type" not in self.stac_config["catalogs"][cat_key].keys() else "get_stac_%s" % self.stac_config["catalogs"][cat_key]["catalog_type"]) get_data_method = getattr(self, get_data_method_name) cat_data_list = get_data_method(catalog_name=cat_key) if idx == len(catalogs) - 1: # filtering values list as children (do not include items) self.set_children([{ "rel": "child", "href": self.url + "/" + str(filtering_data), "title": str(filtering_data), } for filtering_data in cat_data_list]) return self
def search_stac_items(url, arguments, root="/", catalogs=[], provider=None): """Get items collection dict for given catalogs list :param url: requested URL :type url: str :param arguments: request args :type arguments: dict :param root: API root :type root: str :param catalogs: catalogs list :type catalogs: list :param provider: chosen provider :type provider: str :returns: catalog dictionnary :rtype: dict """ collections = arguments.get("collections", None) catalog_url = url.replace("/items", "") # use catalogs from path or if it is empty, collections from args if catalogs: result_catalog = StacCatalog( url=catalog_url, stac_config=stac_config, root=root, provider=provider, eodag_api=eodag_api, catalogs=catalogs, ) elif collections: # get collection as product_type if isinstance(collections, str): collections = collections.split(",") elif not isinstance(collections, list): raise ValidationError("Collections argument type should be Array") result_catalog = StacCatalog( url=catalog_url, stac_config=stac_config, root=root, provider=provider, eodag_api=eodag_api, # handle only one collection per request (STAC allows multiple) catalogs=collections[0:1], ) arguments.pop("collections") else: raise NoMatchingProductType( "No product_type found in collections argument") # get id ids = arguments.get("ids", None) if ids: # handle only one id per request (STAC allows multiple) arguments["id"] = ids.split(",")[0] arguments.pop("ids") # get datetime if "datetime" in arguments.keys(): dtime_split = arguments.get("datetime", "").split("/") if len(dtime_split) > 1: arguments["dtstart"] = (dtime_split[0] if dtime_split[0] != ".." else datetime.datetime.min.isoformat() + "Z") arguments["dtend"] = ( dtime_split[1] if dtime_split[1] != ".." else datetime.datetime.now( datetime.timezone.utc).isoformat().replace("+00:00", "") + "Z") elif len(dtime_split) == 1: # same time for start & end if only one is given arguments["dtstart"], arguments["dtend"] = dtime_split[0:1] * 2 arguments.pop("datetime") search_results = search_products( product_type=result_catalog.search_args["product_type"], arguments=dict(arguments, **result_catalog.search_args, **{"unserialized": "true"}), ) return StacItem( url=url, stac_config=stac_config, provider=provider, eodag_api=eodag_api, root=root, ).get_stac_items( search_results=search_results, catalog=dict( result_catalog.get_stac_catalog(), **{ "url": result_catalog.url, "root": result_catalog.root }, ), )