Skip to content

Commit

Permalink
refactor(indicators): merge all metadata files
Browse files Browse the repository at this point in the history
merge all indicator metadata files into one similar to metadata files of
topics and projects
  • Loading branch information
matthiasschaub committed Sep 26, 2024
1 parent 11d6efb commit dc9873a
Show file tree
Hide file tree
Showing 16 changed files with 122 additions and 152 deletions.
9 changes: 3 additions & 6 deletions ohsome_quality_api/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,12 @@
)
from ohsome_quality_api.attributes.definitions import get_attributes, load_attributes
from ohsome_quality_api.config import configure_logging
from ohsome_quality_api.definitions import (
ATTRIBUTION_URL,
get_metadata,
)
from ohsome_quality_api.definitions import ATTRIBUTION_URL
from ohsome_quality_api.indicators.definitions import (
IndicatorEnum,
IndicatorEnumRequest,
get_coverage,
get_indicator,
get_indicator_metadata,
)
from ohsome_quality_api.projects.definitions import (
Expand All @@ -75,7 +73,6 @@
)
from ohsome_quality_api.utils.helper import (
get_class_from_key,
hyphen_to_camel,
json_serialize,
)
from ohsome_quality_api.utils.validators import (
Expand Down Expand Up @@ -450,7 +447,7 @@ async def metadata_indicators(project: ProjectEnum = DEFAULT_PROJECT) -> Any:
)
async def metadata_indicators_by_key(key: IndicatorEnum) -> Any:
"""Get metadata of an indicator by key."""
metadata = get_metadata("indicators", hyphen_to_camel(key.value))
metadata = get_indicator(key.value)
return {"result": {key.value: metadata}}


Expand Down
30 changes: 1 addition & 29 deletions ohsome_quality_api/definitions.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
"""Global Variables and Functions."""

import glob
import logging
from enum import Enum
from types import MappingProxyType
from typing import Iterable, Literal
from typing import Literal

import yaml

from ohsome_quality_api.indicators.models import IndicatorMetadata
from ohsome_quality_api.topics.definitions import load_topic_presets
from ohsome_quality_api.utils.helper import (
camel_to_hyphen,
get_module_dir,
)

Expand Down Expand Up @@ -77,31 +74,6 @@ def load_metadata(
return metadata


def get_metadata(
module_name: Literal["indicators"], class_name: str
) -> IndicatorMetadata:
"""Get metadata of an indicator based on its class name.
This is implemented outside the metadata class to be able to access metadata of all
indicators without instantiating of those.
Args:
module_name: indicators.
class_name: Class name of an indicator (camel case).
"""
metadata = load_metadata(module_name)
try:
return metadata[camel_to_hyphen(class_name)]
except KeyError:
logging.error("Invalid class name: " + class_name)
raise


# TODO: duplicate of func with the same name in projects/definition.py ?
def get_project_keys() -> Iterable[str]:
return set(t.project for t in load_topic_presets().values())


def get_attribution(data_keys: list) -> str:
"""Return attribution text. Individual attributions are separated by semicolons."""
assert set(data_keys) <= {"OSM", "GHSL", "VNL", "EUBUCCO", "Microsoft Buildings"}
Expand Down
10 changes: 0 additions & 10 deletions ohsome_quality_api/indicators/attribute_completeness/metadata.yaml

This file was deleted.

8 changes: 5 additions & 3 deletions ohsome_quality_api/indicators/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
import yaml
from geojson import Feature, Polygon

from ohsome_quality_api.definitions import get_attribution, get_metadata
from ohsome_quality_api.definitions import get_attribution
from ohsome_quality_api.indicators.definitions import get_indicator
from ohsome_quality_api.indicators.models import (
IndicatorMetadata,
IndicatorTemplates,
Result,
)
from ohsome_quality_api.topics.models import BaseTopic as Topic
from ohsome_quality_api.utils.helper import (
camel_to_hyphen,
camel_to_snake,
get_module_dir,
json_serialize,
Expand All @@ -28,8 +30,8 @@ def __init__(
topic: Topic,
feature: Feature,
) -> None:
self.metadata: IndicatorMetadata = get_metadata(
"indicators", type(self).__name__
self.metadata: IndicatorMetadata = get_indicator(
camel_to_hyphen(type(self).__name__)
)
self.templates: IndicatorTemplates = self.get_template()
self.topic: Topic = topic
Expand Down

This file was deleted.

9 changes: 0 additions & 9 deletions ohsome_quality_api/indicators/currentness/metadata.yaml

This file was deleted.

33 changes: 29 additions & 4 deletions ohsome_quality_api/indicators/definitions.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,51 @@
import os
from enum import Enum

import yaml
from geojson import FeatureCollection

from ohsome_quality_api.definitions import load_metadata
from ohsome_quality_api.indicators.models import IndicatorMetadata
from ohsome_quality_api.projects.definitions import ProjectEnum
from ohsome_quality_api.topics.definitions import load_topic_presets
from ohsome_quality_api.utils.helper import get_class_from_key
from ohsome_quality_api.utils.helper import (
get_class_from_key,
get_module_dir,
)


def get_indicator_keys() -> list[str]:
return list(load_metadata("indicators").keys())
return [str(t) for t in load_indicators().keys()]


def load_indicators() -> dict[str, IndicatorMetadata]:
directory = get_module_dir("ohsome_quality_api.indicators")
file = os.path.join(directory, "indicators.yaml")
with open(file, "r") as f:
raw = yaml.safe_load(f)
indicators = {}
for k, v in raw.items():
indicators[k] = IndicatorMetadata(**v)
return indicators


def get_indicator_metadata(project: ProjectEnum = None) -> dict[str, IndicatorMetadata]:
indicators = load_metadata("indicators")
indicators = load_indicators()
if project is not None:
return {k: v for k, v in indicators.items() if project in v.projects}
else:
return indicators


def get_indicator(indicator_key: str) -> IndicatorMetadata:
indicators = get_indicator_metadata()
try:
return indicators[indicator_key]
except KeyError as error:
raise KeyError(
"Invalid project key. Valid project keys are: " + str(indicators.keys())
) from error


def get_valid_indicators(topic_key: str) -> tuple:
"""Get valid Indicator/Topic combination of a Topic."""
td = load_topic_presets()
Expand Down
10 changes: 0 additions & 10 deletions ohsome_quality_api/indicators/density/metadata.yaml

This file was deleted.

69 changes: 69 additions & 0 deletions ohsome_quality_api/indicators/indicators.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
density:
name: Density
projects:
- experimental
quality_dimension: none
description: >-
The density of features.
It is calculated by the number of features
divided by the area in square-kilometers.
minimal:
name: Minimal
projects:
- misc
quality_dimension: minimal
description: >-
An minimal Indicator for testing purposes.
currentness:
name: Currentness
projects:
- core
- bkg
quality_dimension: currentness
description: >-
Estimate currentness of features by classifying contributions based on
topic specific temporal thresholds into three groups: up-to-date,
in-between and out-of-date.
road-comparison:
name: Road Comparison
projects:
- bkg
- core
quality_dimension: completeness
description: >-
Compare the road length of OSM roads with the road length of
reference data.
mapping-saturation:
name: Mapping Saturation
projects:
- core
- corine-land-cover
- expanse
- experimental
- idealvgi
- mapaction
- sketchmap
- bkg
quality_dimension: completeness
description: >-
Calculate if mapping has saturated.
High saturation has been reached if the growth of the fitted curve is
minimal.
building-comparison:
name: Building Comparison
projects:
- bkg
- core
quality_dimension: completeness
description: >-
Comparison of OSM buildings with the buildings of reference datasets.
attribute-completeness:
name: Attribute Completeness
projects:
- bkg
quality_dimension: completeness
description: >-
Derive the ratio of OSM features compared to features which
match additional expected tags (e.g. amenity=hospital vs
amenity=hospital and wheelchair=yes).
16 changes: 0 additions & 16 deletions ohsome_quality_api/indicators/mapping_saturation/metadata.yaml

This file was deleted.

8 changes: 0 additions & 8 deletions ohsome_quality_api/indicators/minimal/metadata.yaml

This file was deleted.

10 changes: 0 additions & 10 deletions ohsome_quality_api/indicators/road_comparison/metadata.yaml

This file was deleted.

10 changes: 5 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
from geojson import Feature, FeatureCollection, Polygon

from ohsome_quality_api.attributes.models import Attribute
from ohsome_quality_api.definitions import (
get_metadata,
load_metadata,
from ohsome_quality_api.indicators.definitions import (
get_indicator,
get_indicator_metadata,
)
from ohsome_quality_api.indicators.models import IndicatorMetadata
from ohsome_quality_api.projects.definitions import get_project, load_projects
Expand Down Expand Up @@ -241,9 +241,9 @@ def feature_collection_unsupported_geometry_type(request) -> FeatureCollection:

@pytest.fixture
def metadata_indicator_minimal() -> dict[str, IndicatorMetadata]:
return {"minimal": get_metadata("indicators", "Minimal")}
return {"minimal": get_indicator("minimal")}


@pytest.fixture
def indicators_metadata() -> dict[str, IndicatorMetadata]:
return load_metadata("indicators")
return get_indicator_metadata()
28 changes: 0 additions & 28 deletions tests/unittests/test_definitions.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import unittest

import pytest

from ohsome_quality_api import definitions
from ohsome_quality_api.indicators.models import (
IndicatorMetadata as IndicatorMetadata,
Expand All @@ -24,29 +22,3 @@ def test_get_attribution(self):
)

self.assertRaises(AssertionError, definitions.get_attribution, ["MSO"])


def test_load_metadata_indicator():
metadata = definitions.load_metadata("indicators")
assert isinstance(metadata, dict)
for v in metadata.values():
assert isinstance(v, IndicatorMetadata)


def test_load_metadata_wrong_module():
with pytest.raises(AssertionError):
definitions.load_metadata("foo")
with pytest.raises(AssertionError):
definitions.load_metadata("")


def test_get_metadata_indicator():
metadata = definitions.get_metadata("indicators", "Minimal")
assert isinstance(metadata, IndicatorMetadata)


def test_get_metadata_wrong_class():
with pytest.raises(KeyError):
definitions.get_metadata("indicators", "foo")
with pytest.raises(KeyError):
definitions.get_metadata("indicators", "")
4 changes: 2 additions & 2 deletions tests/unittests/test_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import geojson
import numpy as np

from ohsome_quality_api.definitions import load_metadata
from ohsome_quality_api.indicators.definitions import get_indicator_metadata
from ohsome_quality_api.indicators.mapping_saturation import models
from ohsome_quality_api.indicators.minimal.indicator import (
Minimal as MinimalIndicator,
Expand Down Expand Up @@ -40,7 +40,7 @@ def test_name_to_class(self):
MinimalIndicator,
)

self.indicators = load_metadata("indicators")
self.indicators = get_indicator_metadata()
for indicator_name in self.indicators.keys():
self.assertIsNotNone(
get_class_from_key(class_type="indicator", key=indicator_name)
Expand Down
Loading

0 comments on commit dc9873a

Please sign in to comment.