Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dimension metadata and style #19

Merged
merged 6 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 31 additions & 11 deletions examples/create_layers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ common_items:
# Uncomment to set cache age setting (in seconds) for HTTP header responses
# cache_age_max: 86400

# Set the default style to the layer. The style should already exist
default_style:
lahtinep marked this conversation as resolved.
Show resolved Hide resolved
null
# Name of style
# name: raster
# # Workspace of the style
# workspace: Radar

# Property files to be sent.
properties:
indexer.properties:
Expand All @@ -54,17 +62,29 @@ properties:
files:
- /tmp/20200402_1135_empty_EPSG3035.tif

# Settings for the layer time dimension
time_dimension:
# Needs to match with properties -> indexer -> TimeAttribute
name: *time_attribute
enabled: true
# Images are available regularly every 5 minutes
presentation: DISCRETE_INTERVAL
# Time resolution in milliseconds. 300000 = 5 minutes
resolution: 300000
units: ISO8601
nearestMatchEnabled: false
dimensions:
lahtinep marked this conversation as resolved.
Show resolved Hide resolved
# Settings for the layer time dimension
time_dimension:
# Needs to match with properties -> indexer -> TimeAttribute
name: *time_attribute
enabled: true
# Images are available regularly every 5 minutes
presentation: DISCRETE_INTERVAL
# Time resolution in milliseconds. 300000 = 5 minutes
resolution: 300000
units: ISO8601
nearestMatchEnabled: false
elevation_dimension:
# Needs to match with properties -> indexer -> ElevationAttribute
name: elevation
enabled: true
# Presentation in GetCapabilities
presentation: LIST
units: "Degree"
# Set default value strategy
strategy: "MINIMUM"
# Set default unit symbol
unitSymbol: "°"

# List of the mosaics to be created.
# Layers will not be overwritten, but the metadata will be updated
Expand Down
47 changes: 29 additions & 18 deletions georest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def _collect_layer_metadata(config, layer_config):
def _create_layers(config, cat, property_file):
"""Create all configured layers."""
workspace = config["workspace"]
time_dim = config["time_dimension"]
dimensions = config["dimensions"]

# Make sure the workspace exists
create_workspace(workspace, cat)
Expand All @@ -99,14 +99,14 @@ def _create_layers(config, cat, property_file):
utils.write_wkt_for_files(config, layer_directories[layer_name])

if _create_layer(cat, workspace, layer_name, property_file):
if not add_layer_metadata(cat, workspace, layer_name, time_dim, meta):
if not add_layer_metadata(cat, workspace, layer_name, dimensions, meta, style=config.get("default_style")):
continue
# Delete the empty image from database (does not remove the file)
for fname in config["properties"].get("files", []):
delete_granule(cat, workspace, layer_name, fname)


def add_layer_metadata(cat, workspace, layer_name, time_dim, meta):
def add_layer_metadata(cat, workspace, layer_name, dimensions, meta, style=None):
"""Add metadata for the given layer."""
coverage = cat.get_resource(workspace=workspace, store=layer_name)
if coverage is None:
Expand All @@ -120,13 +120,22 @@ def add_layer_metadata(cat, workspace, layer_name, time_dim, meta):
attr = trollsift.compose(attr, meta)
setattr(coverage, attribute, attr)

coverage = _add_time_dimension(coverage, time_dim)
coverage = _add_cache_age_max(coverage, meta.get("cache_age_max", None))
# Add dimensions
for _, dim in dimensions.items():
coverage = add_dimension(coverage, dim)

coverage = _add_cache_age_max(coverage, meta.get("cache_age_max", None))
# Save the added metadata
cat.save(coverage)
logger.info("Metadata written for layer '%s' on workspace '%s'",
layer_name, workspace)

if style is not None:
# Add default style for layer
layer = cat.get_layer(layer_name)
layer._set_default_style(cat.get_style(style["name"], workspace=style["workspace"]))
cat.save(layer)
Comment on lines +131 to +135
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think covering this in the tests would be as simple as setting the default_style in georest.tests.test_geoserver.CREATE_LAYERS_CONFIG dictionary and an assert or two to test_create_layers().

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or even bette, make that a new test case based on test_create_layers() that only checks for the style being handled properly with an assert or two.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I tried to add a test case for the style (but I'm not an expert in tests so I'm not sure if this is how it should be done)

logger.info(
"Metadata written for layer '%s' on workspace '%s'", layer_name, workspace
)
return True


Expand Down Expand Up @@ -166,18 +175,20 @@ def create_layer(cat, workspace, layer, property_file):
logger.info("Layer '%s' created to workspace '%s'", layer, workspace)


def _add_time_dimension(coverage, time_dim):
"""Add time dimension for the layer."""
def add_dimension(coverage, dim):
"""Add dimension for the layer."""
metadata = coverage.metadata.copy()
time_info = DimensionInfo(
time_dim["name"],
time_dim["enabled"],
time_dim["presentation"],
time_dim["resolution"],
time_dim["units"],
None,
nearestMatchEnabled=time_dim["nearestMatchEnabled"])
metadata['time'] = time_info
dim_info = DimensionInfo(
dim["name"],
dim["enabled"],
dim["presentation"],
resolution=dim.get("resolution"),
units=dim.get("units"),
unitSymbol=dim.get("unitSymbol"),
strategy=dim.get("strategy"),
nearestMatchEnabled=dim.get("nearestMatchEnabled"),
)
metadata[dim["name"]] = dim_info
coverage.metadata = metadata

return coverage
Expand Down
60 changes: 44 additions & 16 deletions georest/tests/test_geoserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,22 +83,28 @@ def _create_extra_files(tempdir, files):
return out_files


CREATE_LAYERS_CONFIG = {"host": "host",
"workspace": "workspace",
"common_items": {"cache_age_max": 86400},
"properties": {"foo": {"bar": "baz"}},
"time_dimension": {"name": "name",
"enabled": "enabled",
"presentation": "presentation",
"resolution": "resolution",
"units": "units",
"nearestMatchEnabled": "nearestMatchEnabled"},
"layers": [{"name": "colorized_ir_clouds",
"title": "Title text",
"abstract": "Abstract",
"keywords": ["kw1", "kw2"]},
]
}
CREATE_LAYERS_CONFIG = {
"host": "host",
"workspace": "workspace",
"common_items": {"cache_age_max": 86400},
"properties": {"foo": {"bar": "baz"}},
"dimensions": {
"time_dimension": {
"name": "name",
"enabled": "enabled",
"presentation": "presentation",
"resolution": "resolution",
"units": "units",
"nearestMatchEnabled": "nearestMatchEnabled",
},
},
"layers": [
{"name": "colorized_ir_clouds", "title": "Title text", "abstract": "Abstract", "keywords": ["kw1", "kw2"]},
],
}

CREATE_LAYERS_WITH_STYLE_CONFIG = deepcopy(CREATE_LAYERS_CONFIG)
CREATE_LAYERS_WITH_STYLE_CONFIG["default_style"] = {"name": "style", "workspace": "workspace"}


@mock.patch("georest.DimensionInfo")
Expand Down Expand Up @@ -161,6 +167,28 @@ def test_create_layers_already_exist(connect_to_gs_catalog, DimensionInfo):
assert cat.save.call_count == 2


@mock.patch("georest.connect_to_gs_catalog")
def test_create_layers_with_style(connect_to_gs_catalog):
"""Test creating layers when they already exist."""
import tempfile

from georest import create_layers

config = deepcopy(CREATE_LAYERS_WITH_STYLE_CONFIG)
cat = mock.MagicMock()
coverage = mock.MagicMock()
cat.get_resource.return_value = coverage

connect_to_gs_catalog.return_value = cat

with tempfile.TemporaryDirectory() as tempdir:
config["exposed_base_dir"] = tempdir
create_layers(config.copy())

assert "call.get_style('style', workspace='workspace')" in str(cat.mock_calls)
assert "_set_default_style" in str(cat.mock_calls)


@mock.patch("georest.delete_granule")
@mock.patch("georest.DimensionInfo")
@mock.patch("georest.connect_to_gs_catalog")
Expand Down
Loading