Skip to content

Commit

Permalink
Merge branch 'attribute-completeness-enhancement' of https://github.c…
Browse files Browse the repository at this point in the history
…om/GIScience/ohsome-quality-api into attribute-completeness-enhancement

Updated the indicator plot
  • Loading branch information
Reifenrath committed Aug 28, 2024
2 parents c03b9fc + 016ae53 commit fcb0761
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 39 deletions.
53 changes: 41 additions & 12 deletions ohsome_quality_api/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
)
from ohsome_quality_api.indicators.definitions import (
IndicatorEnum,
IndicatorEnumRequest,
get_coverage,
get_indicator_metadata,
)
Expand Down Expand Up @@ -86,10 +87,7 @@
hyphen_to_camel,
json_serialize,
)
from ohsome_quality_api.utils.validators import (
validate_indicator_attribute_combination,
validate_indicator_topic_combination,
)
from ohsome_quality_api.utils.validators import validate_indicator_topic_combination

MEDIA_TYPE_GEOJSON = "application/geo+json"
MEDIA_TYPE_JSON = "application/json"
Expand Down Expand Up @@ -266,6 +264,31 @@ async def post_indicator_ms(parameters: IndicatorDataRequest) -> CustomJSONRespo
return CustomJSONResponse(content=response, media_type=MEDIA_TYPE_JSON)


@app.post(
"/indicators/attribute-completeness",
tags=["indicator"],
response_model=Union[IndicatorJSONResponse, IndicatorGeoJSONResponse],
responses={
200: {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/IndicatorJSONResponse"}
},
"application/geo+json": {
"schema": {"$ref": "#/components/schemas/IndicatorGeoJSONResponse"}
},
},
},
},
)
async def post_attribute_completeness(
request: Request,
parameters: AttributeCompletenessRequest,
) -> Any:
"""Request the Attribute Completeness indicator for your area of interest."""
return await _post_indicator(request, "attribute-completeness", parameters)


@app.post(
"/indicators/{key}",
tags=["indicator"],
Expand All @@ -285,20 +308,26 @@ async def post_indicator_ms(parameters: IndicatorDataRequest) -> CustomJSONRespo
)
async def post_indicator(
request: Request,
key: IndicatorEnum,
parameters: IndicatorRequest | AttributeCompletenessRequest,
key: IndicatorEnumRequest,
parameters: IndicatorRequest,
) -> Any:
"""Request an indicator for your area of interest."""
validate_indicator_topic_combination(key.value, parameters.topic_key.value)
validate_indicator_attribute_combination(
key.value, getattr(parameters, "attribute_key", None)
)
return await _post_indicator(request, key.value, parameters)


async def _post_indicator(
request: Request, key: str, parameters: IndicatorRequest
) -> Any:
validate_indicator_topic_combination(key, parameters.topic_key.value)
attribute_key = getattr(parameters, "attribute_key", None)
if attribute_key:
attribute_key = attribute_key.value
indicators = await oqt.create_indicator(
key=key.value,
key=key,
bpolys=parameters.bpolys,
topic=get_topic_preset(parameters.topic_key.value),
include_figure=parameters.include_figure,
attribute_key=getattr(parameters, "attribute_key", None),
attribute_key=attribute_key,
)

if request.headers["accept"] == MEDIA_TYPE_JSON:
Expand Down
4 changes: 2 additions & 2 deletions ohsome_quality_api/api/request_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from geojson import FeatureCollection
from pydantic import BaseModel, ConfigDict, Field, field_validator

from ohsome_quality_api.attributes.definitions import AttributeEnum
from ohsome_quality_api.topics.definitions import TopicEnum
from ohsome_quality_api.topics.models import TopicData
from ohsome_quality_api.utils.helper import snake_to_lower_camel
Expand Down Expand Up @@ -63,8 +64,7 @@ class IndicatorRequest(BaseBpolys):


class AttributeCompletenessRequest(IndicatorRequest):
# TODO: Should be AttributeEnum
attribute_key: str = Field(
attribute_key: AttributeEnum = Field(
...,
title="Attribute Key",
alias="attribute",
Expand Down
10 changes: 10 additions & 0 deletions ohsome_quality_api/attributes/definitions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
from enum import Enum
from typing import List

import yaml
Expand Down Expand Up @@ -68,3 +69,12 @@ def build_attribute_filter(attribute_key: List[str], topic_key: str) -> str:
return attribute_filter
except KeyError as error:
raise KeyError("Invalid topic or attribute key(s).") from error


attribute_keys = {
inner_key
for outer_dict in load_attributes().values()
for inner_key in outer_dict.keys()
}

AttributeEnum = Enum("AttributeEnum", {name: name for name in attribute_keys})
4 changes: 4 additions & 0 deletions ohsome_quality_api/indicators/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ async def get_coverage(indicator_key: str, inverse: bool = False) -> FeatureColl


IndicatorEnum = Enum("IndicatorEnum", {name: name for name in get_indicator_keys()})
IndicatorEnumRequest = Enum(
"IndicatorEnum",
{name: name for name in get_indicator_keys() if name != "attribute-completeness"},
)
13 changes: 0 additions & 13 deletions ohsome_quality_api/utils/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,6 @@ def __init__(self, indicator, topic):
)


class IndicatorAttributeCombinationError(ValidationError):
"""Invalid indicator topic combination error."""

def __init__(self, indicator, attribute):
self.name = "IndicatorAttributeCombinationError"
self.message = (
"Invalid combination of indicator and attribute: {} and {}".format(
indicator,
attribute,
)
)


class OhsomeApiError(Exception):
"""Request to ohsome API failed."""

Expand Down
8 changes: 0 additions & 8 deletions ohsome_quality_api/utils/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
GeoJSONError,
GeoJSONGeometryTypeError,
GeoJSONObjectTypeError,
IndicatorAttributeCombinationError,
IndicatorTopicCombinationError,
InvalidCRSError,
SizeRestrictionError,
Expand All @@ -20,13 +19,6 @@ def validate_indicator_topic_combination(indicator: str, topic: str):
raise IndicatorTopicCombinationError(indicator, topic)


def validate_indicator_attribute_combination(indicator: str, attribute: str | None):
if indicator == "attribute-completeness" and attribute is None:
raise IndicatorAttributeCombinationError(indicator, attribute)
elif indicator != "attribute-completeness" and attribute is not None:
raise IndicatorAttributeCombinationError(indicator, attribute)


def validate_geojson(bpolys: GeoJSON):
"""Validate GeoJSON object."""
if not bpolys.is_valid:
Expand Down
7 changes: 3 additions & 4 deletions tests/integrationtests/api/test_indicators.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def test_indicators_attribute_completeness_without_attribute(
response = client.post(endpoint, json=parameters, headers=headers)
assert response.status_code == 422
content = response.json()
assert content["type"] == "IndicatorAttributeCombinationError"
assert content["type"] == "RequestValidationError"


@oqapi_vcr.use_cassette
Expand Down Expand Up @@ -202,8 +202,7 @@ def test_minimal_additional_parameter_foo(client, bpolys, headers, schema):
response = client.post(endpoint, json=parameters, headers=headers)
assert response.status_code == 422
content = response.json()
# TODO
assert content["type"] != "IndicatorAttributeCombinationError"
assert content["type"] == "RequestValidationError"


@oqapi_vcr.use_cassette
Expand All @@ -213,7 +212,7 @@ def test_minimal_additional_parameter_attribute(client, bpolys, headers, schema)
response = client.post(endpoint, json=parameters, headers=headers)
assert response.status_code == 422
content = response.json()
assert content["type"] == "IndicatorAttributeCombinationError"
assert content["type"] == "RequestValidationError"


def test_bpolys_size_limit(client, europe, headers, schema):
Expand Down

0 comments on commit fcb0761

Please sign in to comment.