def __init__(self, product, band_cfg, dc): self.product = product self.product_name = product.name self.native_bands = dc.list_measurements().loc[self.product_name] if band_cfg is None: self.band_cfg = {} for b in self.native_bands.index: self.band_cfg[b] = [] else: self.band_cfg = band_cfg self._idx = {} self._nodata_vals = {} for b, aliases in self.band_cfg.items(): if b not in self.native_bands.index: raise ConfigException(f"Unknown band: {b} in layer {product}") if b in self._idx: raise ConfigException( f"Duplicate band name/alias: {b} in layer {product}") self._idx[b] = b for a in aliases: if a != b and a in self._idx: raise ConfigException( f"Duplicate band name/alias: {a} in layer {product}") self._idx[a] = b self._nodata_vals[b] = self.native_bands['nodata'][b] if isinstance(self._nodata_vals[b], str) and self._nodata_vals[b].lower() == "nan": self._nodata_vals[b] = float("nan")
def parse_pq_names(self, cfg): if "datasets" in cfg: raise ConfigException( f"The 'datasets' entry in the flags section is no longer supported. Please refer to the documentation for the correct format (layer {self.name})" ) if "products" in cfg: pq_names = tuple(cfg["products"]) else: pq_names = self.product_names if "low_res_products" in cfg: pq_low_res_names = tuple(cfg["low_res_products"]) else: pq_low_res_names = self.low_res_product_names if "product" in cfg: raise ConfigException( f"'product' entry in flags section of multi-product layer {self.name} - use 'products' only" ) if "low_res_product" in cfg: raise ConfigException( f"'low_res_product' entry in flags section of multi-product layer {self.name} - use 'low_res_products' only" ) return { "pq_names": pq_names, "pq_low_res_names": pq_low_res_names, }
def __init__(self, identifier, cfg, global_cfg): super().__init__(cfg) self.global_cfg = global_cfg self.identifier = identifier self.crs_name = cfg["crs"] if self.crs_name not in self.global_cfg.published_CRSs: raise ConfigException( f"Tile matrix set {identifier} has unpublished CRS: {self.crs_name}" ) self.matrix_origin = cfg["matrix_origin"] validate_2d_array(self.matrix_origin, identifier, "Matrix origin", float) self.tile_size = cfg["tile_size"] validate_2d_array(self.tile_size, identifier, "Tile size", int) self.scale_set = cfg["scale_set"] try: validate_array_typ(self.scale_set, identifier, "Scale set", float) except TypeError: raise ConfigException( f"In tile matrix set {identifier}, scale_set is not a list") if len(self.scale_set) < 1: raise ConfigException( f"Tile matrix set {identifier} has no scale denominators in scale_set" ) self.force_raw_crs_name = bool(cfg.get("force_raw_crs_name", False)) self.wkss = cfg.get("wkss") self.initial_matrix_exponents = cfg.get( "matrix_exponent_initial_offsets", (0, 0)) validate_2d_array(self.initial_matrix_exponents, identifier, "Initial matrix exponents", int) self.unit_coefficients = cfg.get("unit_coefficients", (1.0, -1.0)) validate_2d_array(self.unit_coefficients, identifier, "Unit coefficients", float)
def parse_pq_names(self, cfg): # pylint: disable=attribute-defined-outside-init if "datasets" in cfg: self.pq_names = cfg["datasets"] print("CFG WARNING:", "The preferred name for the 'datasets' entry", "in the flags section is now 'products'.", "Please update the configuration for layer", self.name) elif "products" in cfg: self.pq_names = cfg["products"] else: self.pq_names = list(self.product_names) self.pq_name = self.pq_names[0] if "low_res_products" in cfg: self.pq_low_res_names = cfg["low_res_products"] self.pq_low_res_name = self.pq_names[0] else: self.pq_low_res_names = list(self.low_res_product_names) self.pq_low_res_name = self.low_res_product_name if "product" in cfg: raise ConfigException( f"'product' entry in flags section of multi-product layer {self.name} - use 'products' only" ) if "low_res_product" in cfg: raise ConfigException( f"'low_res_product' entry in flags section of multi-product layer {self.name} - use 'low_res_products' only" )
def __init__(self, refresh=False): if not self.initialised or refresh: self.initialised = True cfg = read_config() try: self.parse_global(cfg["global"]) except KeyError as e: raise ConfigException( "Missing required config entry in 'global' section: %s" % str(e)) if self.wms: self.parse_wms(cfg.get("wms", {})) else: self.parse_wms({}) if self.wcs: try: self.parse_wcs(cfg["wcs"]) except KeyError as e: raise ConfigException( "Missing required config entry in 'wcs' section (with WCS enabled): %s" % str(e)) else: self.parse_wcs(None) try: self.parse_layers(cfg["layers"]) except KeyError as e: raise ConfigException( "Missing required config entry in 'layers' section") super().__init__({})
def ready_flags(self, dc): if self.pq_names: for pqn in self.pq_names: if pqn is not None: pq_product = dc.index.products.get_by_name(pqn) if pq_product is None: raise ConfigException( f"Could not find flags product {pqn} for layer {self.name} in datacube" ) self.pq_products.append(pq_product) if self.pq_low_res_names: for pqn in self.pq_low_res_names: if pqn is not None: pq_product = dc.index.products.get_by_name(pqn) if pq_product is None: raise ConfigException( f"Could not find flags low_res product {pqn} for layer {self.name} in datacube" ) self.pq_low_res_products.append(pq_product) self.info_mask = ~0 if self.pq_products: self.pq_product = self.pq_products[0] meas = self.pq_product.lookup_measurements([self.pq_band]) self.flags_def = meas[self.pq_band]["flags_definition"] for bitname in self.ignore_info_flags: bit = self.flags_def[bitname]["bits"] if not isinstance(bit, int): continue flag = 1 << bit self.info_mask &= ~flag else: self.flags_def = None self.pq_product = None
def parse_wcs(self, cfg): if self.wcs: if not isinstance(cfg, Mapping): raise ConfigException( "WCS section missing (and WCS is enabled)") self.wcs_formats = WCSFormat.from_cfg(cfg["formats"]) self.wcs_formats_by_name = { fmt.name: fmt for fmt in self.wcs_formats } self.wcs_formats_by_mime = { fmt.mime: fmt for fmt in self.wcs_formats } if not self.wcs_formats: raise ConfigException( "Must configure at least one wcs format to support WCS.") self.native_wcs_format = cfg["native_format"] if self.native_wcs_format not in self.wcs_formats_by_name: raise ConfigException( f"Configured native WCS format ({self.native_wcs_format}) not a supported format." ) else: self.default_geographic_CRS = None self.default_geographic_CRS_def = None self.wcs_formats = [] self.wcs_formats_by_name = {} self.wcs_formats_by_mime = {} self.native_wcs_format = None
def parse_legend_ticks(self, cfg): # Ticks ticks = [] if "ticks_every" in cfg: if "tick_count" in cfg: raise ConfigException( "Cannot use tick count and ticks_every in the same legend") if "ticks" in cfg: raise ConfigException( "Cannot use ticks and ticks_every in the same legend") delta = Decimal(cfg["ticks_every"]) tickval = self.legend_begin while tickval < self.legend_end: ticks.append(tickval) tickval += delta ticks.append(tickval) if "ticks" in cfg: if "tick_count" in cfg: raise ConfigException( "Cannot use tick count and ticks in the same legend") ticks = [Decimal(t) for t in cfg["ticks"]] if not ticks: count = int(cfg.get("tick_count", 1)) if count < 0: raise ConfigException("tick_count cannot be negative") delta = self.legend_end - self.legend_begin dcount = Decimal(count) for i in range(0, count + 1): tickval = self.legend_begin + (Decimal(i) / dcount) * delta ticks.append( tickval.quantize(self.rounder, rounding=ROUND_HALF_UP)) # pylint: disable=attribute-defined-outside-init self.ticks = ticks
def make_ready(self, dc, *args, **kwargs): self.pq_products = [] self.pq_low_res_products = [] for pqn in self.pq_names: if pqn is not None: pq_product = dc.index.products.get_by_name(pqn) if pq_product is None: raise ConfigException( f"Could not find flags product {pqn} for layer {self.product.name} in datacube" ) self.pq_products.append(pq_product) for pqn in self.pq_low_res_names: if pqn is not None: pq_product = dc.index.products.get_by_name(pqn) if pq_product is None: raise ConfigException( f"Could not find flags low_res product {pqn} for layer {self.product.name} in datacube" ) self.pq_low_res_products.append(pq_product) self.info_mask = ~0 # A (hopefully) representative product product = self.pq_products[0] meas = product.lookup_measurements([self.pq_band]) self.flags_def = meas[self.pq_band]["flags_definition"] for bitname in self.ignore_info_flags: bit = self.flags_def[bitname]["bits"] if not isinstance(bit, int): continue flag = 1 << bit self.info_mask &= ~flag super().make_ready(dc)
def __init__(self, cfg, parent_layer=None, **kwargs): super().__init__(cfg, **kwargs) self.global_cfg = kwargs["global_cfg"] self.parent_layer = parent_layer if "title" not in cfg: raise ConfigException( "Layer without title found under parent layer %s" % str(parent_layer)) self.title = cfg["title"] if "abstract" in cfg: self.abstract = cfg["abstract"] elif parent_layer: self.abstract = parent_layer.abstract else: raise ConfigException( "No abstract supplied for top-level layer %s" % self.title) # Accumulate keywords self.keywords = set() if self.parent_layer: for word in self.parent_layer.keywords: self.keywords.add(word) else: for word in self.global_cfg.keywords: self.keywords.add(word) for word in cfg.get("keywords", []): self.keywords.add(word) # Inherit or override attribution if "attribution" in cfg: self.attribution = AttributionCfg.parse(cfg.get("attribution")) elif parent_layer: self.attribution = self.parent_layer.attribution else: self.attribution = self.global_cfg.attribution
def parse_wcs(self, cfg): if self.wcs: if not isinstance(cfg, Mapping): raise ConfigException("WCS section missing (and WCS is enabled)") self.default_geographic_CRS = cfg.get("default_geographic_CRS") if self.default_geographic_CRS not in self.published_CRSs: raise ConfigException("Configured default geographic CRS not listed in published CRSs.") if not self.published_CRSs[self.default_geographic_CRS]["geographic"]: raise ConfigException("Configured default geographic CRS not listed in published CRSs as geographic.") self.default_geographic_CRS_def = self.published_CRSs[self.default_geographic_CRS] self.wcs_formats = {} for fmt_name, fmt in cfg["formats"].items(): self.wcs_formats[fmt_name] = { "mime": fmt["mime"], "extension": fmt["extension"], "multi-time": fmt["multi-time"], "name": fmt_name, } self.wcs_formats[fmt_name]["renderer"] = get_function(fmt["renderer"]) if not self.wcs_formats: raise ConfigException("Must configure at least one wcs format to support WCS.") self.native_wcs_format = cfg["native_format"] if self.native_wcs_format not in self.wcs_formats: raise Exception("Configured native WCS format not a supported format.") else: self.default_geographic_CRS = None self.default_geographic_CRS_def = None self.wcs_formats = {} self.native_wcs_format = None
def __init__(self, cfg, global_cfg, dc, parent_layer=None): self.global_cfg = global_cfg self.parent_layer = parent_layer if "title" not in cfg: raise ConfigException("Layer without title found under parent layer %s" % str(parent_layer)) self.title = cfg["title"] try: if "abstract" in cfg: self.abstract = cfg["abstract"] elif parent_layer: self.abstract = parent_layer.abstract else: raise ConfigException("No abstract supplied for top-level layer %s" % self.title) # Accumulate keywords self.keywords = set() if self.parent_layer: for word in self.parent_layer.keywords: self.keywords.add(word) else: for word in self.global_cfg.keywords: self.keywords.add(word) for word in cfg.get("keywords", []): self.keywords.add(word) # Inherit or override attribution if "attribution" in cfg: self.attribution = AttributionCfg.parse(cfg.get("attribution")) elif parent_layer: self.attribution = self.parent_layer.attribution else: self.attribution = self.global_cfg.attribution except KeyError: raise ConfigException("Required entry missing in layer %s" % self.title) super().__init__({})
def validate_2d_array(array, ident, label, typ): try: if len(array) != 2: raise ConfigException( f"In tile matrix set {ident}, {label} must have two values: f{array}" ) validate_array_typ(array, ident, label, typ) except TypeError: raise ConfigException( f"In tile matrix set {ident}, {label} must be a list of two values: f{array}" )
def add_aliases(self, cfg): for b, aliases in cfg.items(): if b in self._idx: raise ConfigException( f"Duplicate band name/alias: {b} in layer {self.product_name}" ) self._idx[b] = b for a in aliases: if a != b and a in self._idx: raise ConfigException( f"Duplicate band name/alias: {a} in layer {self.product_name}" ) self._idx[a] = b
def parse_wmts(self, cfg): tms_cfgs = TileMatrixSet.default_tm_sets.copy() if "tile_matrix_sets" in cfg: for identifier, tms in cfg["tile_matrix_sets"].items(): tms_cfgs[identifier] = tms self.tile_matrix_sets = {} for identifier, tms in tms_cfgs.items(): if len(identifier.split()) != 1: raise ConfigException(f"Invalid identifier: {identifier}") if identifier in self.tile_matrix_sets: raise ConfigException( f"Tile matrix set identifiers must be unique: {identifier}" ) self.tile_matrix_sets[identifier] = TileMatrixSet( identifier, tms, self)
def __init__(self, product, style_cfg, stand_alone=False, defer_multi_date=False): super(ColorRampDef, self).__init__(product, style_cfg, stand_alone=stand_alone, defer_multi_date=defer_multi_date) style_cfg = self._raw_cfg self.color_ramp = ColorRamp(self, style_cfg) for band in style_cfg["needed_bands"]: self.raw_needed_bands.add(band) self.include_in_feature_info = style_cfg.get("include_in_feature_info", True) if "index_function" in style_cfg: self.index_function = FunctionWrapper(self, style_cfg["index_function"], stand_alone=self.stand_alone) else: raise ConfigException( "Index function is required for index and hybrid styles. Style %s in layer %s" % (self.name, self.product.name)) if not defer_multi_date: self.parse_multi_date(style_cfg)
def parse_wcs(self, cfg): if cfg is None: self.wcs = False return else: self.wcs = True # Native CRS self.cfg_native_crs = cfg.get("native_crs") self.declare_unready("native_CRS") self.declare_unready("native_CRS_def") # Rectified Grids self.declare_unready("origin_x") self.declare_unready("origin_y") self.cfg_native_resolution = cfg.get("native_resolution") self.declare_unready("resolution_x") self.declare_unready("resolution_y") self.declare_unready("grid_high_x") self.declare_unready("grid_high_y") self.declare_unready("grids") # Band management self.wcs_raw_default_bands = cfg["default_bands"] self.declare_unready("wcs_default_bands") # Native format if "native_format" in cfg: self.native_format = cfg["native_format"] if self.native_format not in self.global_cfg.wcs_formats_by_name: raise ConfigException( f"WCS native format {self.native_format} for layer {self.name} is not in supported formats list" ) else: self.native_format = self.global_cfg.native_wcs_format
def parse_flags(self, cfg): self.flag_bands = {} if cfg: if isinstance(cfg, dict): fb = OWSFlagBand(cfg, self) self.flag_bands[fb.pq_band] = fb _LOG.warning( "Single flag bands not in a list is deprecated. Please refer to the documentation for the new format (layer %s)", self.name) else: for fb_cfg in cfg: fb = OWSFlagBand(fb_cfg, self) self.flag_bands[fb.pq_band] = fb pq_names_to_lowres_names = {} for fb in self.flag_bands.values(): pns = fb.pq_names lrpns = fb.pq_low_res_names if pns in pq_names_to_lowres_names and pq_names_to_lowres_names[ pns] != lrpns: raise ConfigException( f"Product name mismatch in flags section for layer {self.name}: product_names {pns} has multiple distinct low-res product names" ) pq_names_to_lowres_names[pns] = lrpns # pylint: disable=dict-values-not-iterating self.allflag_productbands = FlagProductBands.build_list_from_flagbands( self.flag_bands.values())
def parse_product_names(self, cfg): self.product_names = cfg["product_names"] self.product_name = self.product_names[0] self.low_res_product_names = cfg.get("low_res_product_names", []) if self.low_res_product_names: self.low_res_product_name = self.low_res_product_names[0] else: self.low_res_product_name = None if "product_name" in cfg: raise ConfigException( f"'product_name' entry in multi-product layer {self.name} - use 'product_names' only" ) if "low_res_product_name" in cfg: raise ConfigException( f"'low_res_product_name' entry in multi-product layer {self.name} - use 'low_res_product_names' only" )
def cfg_expand(cfg_unexpanded, cwd=None, inclusions=[]): # inclusions defaulting to an empty list is dangerous, but note that it is never modified. # If modification of inclusions is a required, a copy (ninclusions) is made and modified instead. if cwd is None: cwd = os.getcwd() if isinstance(cfg_unexpanded, Mapping): if "include" in cfg_unexpanded: if cfg_unexpanded["include"] in inclusions: raise ConfigException("Cyclic inclusion: %s" % cfg_unexpanded["include"]) ninclusions = inclusions.copy() ninclusions.append(cfg_unexpanded["include"]) # Perform expansion if "type" not in cfg_unexpanded or cfg_unexpanded["type"] == "json": # JSON Expansion raw_path = cfg_unexpanded["include"] try: # Try in actual working directory json_obj = load_json_obj(raw_path) abs_path = os.path.abspath(cfg_unexpanded["include"]) cwd = os.path.dirname(abs_path) # pylint: disable=broad-except except Exception: json_obj = None if json_obj is None: path = os.path.join(cwd, raw_path) try: # Try in inherited working directory json_obj = load_json_obj(path) abs_path = os.path.abspath(path) cwd = os.path.dirname(abs_path) # pylint: disable=broad-except except Exception: json_obj = None if json_obj is None: raise ConfigException("Could not find json file %s" % raw_path) return cfg_expand(load_json_obj(abs_path), cwd=cwd, inclusions=ninclusions) elif cfg_unexpanded["type"] == "python": # Python Expansion return cfg_expand(import_python_obj(cfg_unexpanded["include"]), cwd=cwd, inclusions=ninclusions) else: raise ConfigException("Unsupported inclusion type: %s" % str(cfg_unexpanded["type"])) else: return { k: cfg_expand(v, cwd=cwd, inclusions=inclusions) for k,v in cfg_unexpanded.items() } elif isinstance(cfg_unexpanded, Sequence) and not isinstance(cfg_unexpanded, str): return list([cfg_expand(elem, cwd=cwd, inclusions=inclusions) for elem in cfg_unexpanded ]) else: return cfg_unexpanded
def add_flag_band(self, fb): self.flag_bands[fb.pq_band] = fb self.bands.add(fb.pq_band) if fb.pq_manual_merge: fb.pq_manual_merge = True if fb.pq_fuse_func and self.fuse_func and fb.pq_fuse_func != self.fuse_func: raise ConfigException( f"Fuse functions for flag bands in product set {self.product_names} do not match" ) if fb.pq_ignore_time != self.ignore_time: raise ConfigException( f"ignore_time option for flag bands in product set {self.product_names} do not match" ) elif fb.pq_fuse_func and not self.fuse_func: self.fuse_func = fb.pq_fuse_func self.declare_unready("products") self.declare_unready("low_res_products")
def __init__(self, cfg, keyvals, *args, **kwargs): super().__init__(cfg, *args, **kwargs) for k in self.INDEX_KEYS: if k not in keyvals: raise ConfigException( f"Key value {k} missing from keyvals: {keyvals!r}") self.keyvals = keyvals
def lookup(self, cfg, keyvals, subs=None): if subs is None: subs = {} for k in self.INDEX_KEYS: if k not in keyvals: raise ConfigException( f"Key value {k} missing from keyvals: {keyvals!r}") return self.lookup_impl(cfg, keyvals, subs)
def parse_product_names(self, cfg): self.product_name = cfg["product_name"] self.product_names = (self.product_name, ) self.low_res_product_name = cfg.get("low_res_product_name") if self.low_res_product_name: self.low_res_product_names = (self.low_res_product_name, ) else: self.low_res_product_names = tuple() if "product_names" in cfg: raise ConfigException( f"'product_names' entry in non-multi-product layer {self.name} - use 'product_name' only" ) if "low_res_product_names" in cfg: raise ConfigException( f"'low_res_product_names' entry in non-multi-product layer {self.name} - use 'low_res_product_name' only" )
def __init__(self, cfg, layer_cfg, max_datasets): super().__init__(cfg) self.rules = cfg self.use_caching = self.rules is not None self.max_datasets = max_datasets if not self.use_caching: return min_so_far = 0 max_max_age_so_far = 0 for rule in self.rules: if "min_datasets" not in rule: raise ConfigException( f"Dataset cache rule does not contain a 'min_datasets' element in layer {layer_cfg.name}" ) if "max_age" not in rule: raise ConfigException( f"Dataset cache rule does not contain a 'max_age' element in layer {layer_cfg.name}" ) min_datasets = rule["min_datasets"] max_age = rule["max_age"] if not isinstance(min_datasets, int): raise ConfigException( f"Dataset cache rule has non-integer 'min_datasets' element in layer {layer_cfg.name}" ) if not isinstance(max_age, int): raise ConfigException( f"Dataset cache rule has non-integer 'max_age' element in layer {layer_cfg.name}" ) if min_datasets <= 0: raise ConfigException( f"Invalid dataset cache rule in layer {layer_cfg.name}: min_datasets must be greater than zero." ) if min_datasets <= min_so_far: raise ConfigException( f"Dataset cache rules must be sorted by ascending min_datasets values. In layer {layer_cfg.name}." ) if max_datasets > 0 and min_datasets > max_datasets: raise ConfigException( f"Dataset cache rule min_datasets value exceeds the max_datasets limit in layer {layer_cfg.name}." ) min_so_far = min_datasets if max_age <= 0: raise ConfigException( f"Dataset cache rule max_age value must be greater than zero in layer {layer_cfg.name}." ) if max_age <= max_max_age_so_far: raise ConfigException( f"max_age values in dataset cache rules must increase monotonically in layer {layer_cfg.name}." ) max_max_age_so_far = max_age
def make_ready(self, dc, *args, **kwargs): self.products = [] self.low_res_products = [] for i, prod_name in enumerate(self.product_names): if self.low_res_product_names: low_res_prod_name = self.low_res_product_names[i] else: low_res_prod_name = None product = dc.index.products.get_by_name(prod_name) if not product: raise ConfigException( f"Could not find product {prod_name} in datacube for layer {self.name}" ) self.products.append(product) if low_res_prod_name: product = dc.index.products.get_by_name(low_res_prod_name) if not product: raise ConfigException( f"Could not find product {low_res_prod_name} in datacube for layer {self.name}" ) self.low_res_products.append(product) self.product = self.products[0] self.definition = self.product.definition self.force_range_update(dc) self.band_idx.make_ready(dc) self.all_flag_band_names = set() for fb in self.flag_bands.values(): fb.make_ready(dc) if fb.pq_band in self.all_flag_band_names: raise ConfigException( f"Duplicate flag band name: {fb.pq_band}") self.all_flag_band_names.add(fb.pq_band) self.ready_image_processing(dc) if self.global_cfg.wcs: self.ready_wcs(dc) for style in self.styles: style.make_ready(dc, *args, **kwargs) for fpb in self.allflag_productbands: fpb.make_ready(dc, *args, **kwargs) if not self.multi_product: self.global_cfg.native_product_index[self.product_name] = self if not self.hide: super().make_ready(dc, *args, **kwargs)
def crs(self, crsid): if crsid not in self.published_CRSs: raise ConfigException(f"CRS {crsid} is not published") crs_def = self.published_CRSs[crsid] crs_alias = crs_def["alias_of"] if crs_alias: use_crs = crs_alias else: use_crs = crsid return geometry.CRS(use_crs)
def __init__(self, product, style_cfg, local_band_map=None, stand_alone=False, defer_multi_date=False): super().__init__(product, style_cfg, stand_alone=stand_alone, defer_multi_date=defer_multi_date) style_cfg = self._raw_cfg self.raw_rgb_components = {} for imgband in ["red", "green", "blue", "alpha"]: components = style_cfg["components"].get(imgband) if components is None: if imgband == "alpha": continue else: raise ConfigException( f"No components defined for {imgband} band in style {self.name}, layer {product.name}" ) if "function" in components: self.raw_rgb_components[imgband] = FunctionWrapper( self.product, components, stand_alone=self.stand_alone) for b in style_cfg["additional_bands"]: self.raw_needed_bands.add(b) else: self.raw_rgb_components[imgband] = components for k in components.keys(): if k != "scale_range": self.raw_needed_bands.add(k) self.declare_unready("rgb_components") self.scale_factor = style_cfg.get("scale_factor") if "scale_range" in style_cfg: self.scale_min, self.scale_max = style_cfg["scale_range"] elif self.scale_factor: self.scale_min = 0.0 self.scale_max = 255.0 * self.scale_factor else: self.scale_min = None self.scale_max = None self.component_scale_ranges = {} for cn, cd in style_cfg["components"].items(): if "scale_range" in cd: self.component_scale_ranges[cn] = { "min": cd["scale_range"][0], "max": cd["scale_range"][1], } else: self.component_scale_ranges[cn] = { "min": self.scale_min, "max": self.scale_max, }
def parse_wcs(self, cfg, dc): if cfg is None: self.wcs = False return else: self.wcs = True # Native CRS try: self.native_CRS = self.product.definition["storage"]["crs"] except KeyError: self.native_CRS = None if not self.native_CRS: self.native_CRS = cfg.get("native_crs") if not self.native_CRS: raise ConfigException("No native CRS could be found for layer %s" % self.name) if self.native_CRS not in self.global_cfg.published_CRSs: raise ConfigException("Native CRS for product %s (%s) not in published CRSs" % ( self.product_name, self.native_CRS)) self.native_CRS_def = self.global_cfg.published_CRSs[self.native_CRS] # Prepare Rectified Grid native_bounding_box = self.bboxes[self.native_CRS] self.origin_x = native_bounding_box["left"] self.origin_y = native_bounding_box["bottom"] try: self.resolution_x, self.resolution_y = cfg["native_resolution"] except KeyError: raise ConfigException("No native resolution supplied for WCS enabled layer %s" % self.name) except ValueError: raise ConfigException("Invalid native resolution supplied for WCS enabled layer %s" % self.name) except TypeError: raise ConfigException("Invalid native resolution supplied for WCS enabled layer %s" % self.name) self.grid_high_x = int((native_bounding_box["right"] - native_bounding_box["left"]) / self.resolution_x) self.grid_high_y = int((native_bounding_box["top"] - native_bounding_box["bottom"]) / self.resolution_y) # Band management self.wcs_default_bands = [self.band_idx.band(b) for b in cfg["default_bands"]] # Cache some metadata from the datacube bands = dc.list_measurements().loc[self.product_name] self.bands = bands.index.values self.nodata_values = bands['nodata'].values self.nodata_dict = {a: b for a, b in zip(self.bands, self.nodata_values)}
def parse_styling(self, cfg): self.styles = list([StyleDef(self, s) for s in cfg["styles"]]) self.style_index = {s.name: s for s in self.styles} if "default_style" in cfg: if cfg["default_style"] not in self.style_index: raise ConfigException( "Default style %s is not in the 'styles' for layer %s" % (cfg["default_style"], self.name)) self.default_style = self.style_index[cfg["default_style"]] else: self.default_style = self.styles[0]