Skip to content

Commit

Permalink
Merge pull request #214 from EURODEO/issue_178-levels_multiple_range
Browse files Browse the repository at this point in the history
Issue 178 levels filtering with combination
  • Loading branch information
fjugipe authored Nov 22, 2024
2 parents 32838ee + cd4cb01 commit 939cfd0
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 15 deletions.
8 changes: 8 additions & 0 deletions api/openapi/custom_dimension_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
"summary": "Open start range",
"value": "../10.0",
},
"Combination": {
"summary": "Combination",
"value": "1.0, 1.5/1.8, R5/2.0/2.0",
},
}

periods = {
Expand All @@ -54,6 +58,10 @@
"summary": "Open end range",
"value": "PT0S/..",
},
"Combination": {
"summary": "Combination",
"value": "PT0S, PT1M/PT10M",
},
}

methods = {
Expand Down
19 changes: 19 additions & 0 deletions api/test/test_api_utilities.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import pytest

from utilities import get_levels_values

levels_in_out = [
("1", ["100"]),
("1,2", ["100", "200"]),
("1,2, 3", ["100", "200", "300"]),
("1/3", ["100/300"]),
("../3", ["../300"]),
("1/..", ["100/.."]),
("R3/1.2/0.3", ["120", "150", "180"]),
("1, 3/5, R3/5/0.1,11", ["100", "300/500", "500", "510", "520", "1100"]),
]


@pytest.mark.parametrize("levels_in, levels_out", levels_in_out)
def test_get_levels_values(levels_in, levels_out):
assert get_levels_values(levels_in) == levels_out
30 changes: 30 additions & 0 deletions api/test/test_edr.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,3 +410,33 @@ def test_get_data_with_lowercase_period_range_without_existing_data():

assert response.status_code == 404
assert response.json() == {"detail": "Requested data not found."}


def test_get_data_with_combination_levels_filtering():
with patch("routers.edr.get_obs_request") as mock_get_obs_request:

# Load with random test data for making a mock_obs_request
test_data = load_json("test/test_data/test_coverages_proto.json")
mock_get_obs_request.return_value = create_mock_obs_response(test_data)

response = client.get("/collections/observations/locations/0-20000-0-06260?levels=R6/0.0/0.1, 1.5/1.8, 10")

m_args = mock_get_obs_request.call_args[0][0]

assert response.status_code == 200
assert m_args.filter["level"].values == ["0", "10", "20", "30", "40", "50", "150/180", "1000"]


def test_get_data_with_combination_periods_filtering():
with patch("routers.edr.get_obs_request") as mock_get_obs_request:

# Load with random test data for making a mock_obs_request
test_data = load_json("test/test_data/test_coverages_proto.json")
mock_get_obs_request.return_value = create_mock_obs_response(test_data)

response = client.get("/collections/observations/locations/0-20000-0-06260?periods=PT0S, PT1M/PT10M")

m_args = mock_get_obs_request.call_args[0][0]

assert response.status_code == 200
assert m_args.filter["period"].values == ["0", "60/600"]
46 changes: 31 additions & 15 deletions api/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from datetime import datetime
from datetime import timedelta
from typing import Tuple
from itertools import chain

from isodate import ISO8601Error
import datastore_pb2 as dstore
Expand Down Expand Up @@ -155,7 +156,7 @@ async def add_request_parameters(
request.filter["standard_name"].values.extend(split_and_strip(standard_names))

if levels:
request.filter["level"].values.extend(get_z_levels_or_range(levels))
request.filter["level"].values.extend(get_levels_values(levels))

if methods:
request.filter["function"].values.extend(split_and_strip(methods))
Expand All @@ -179,25 +180,40 @@ def get_periods_or_range(periods: str) -> list[str]:
raise HTTPException(status_code=400, detail=f"{err}")


def get_z_levels_or_range(z: str) -> list[str]:
def get_levels_values(levels: str) -> list[str]:
"""
Function for getting the levels as a list or a range
Function for getting the levels filters as a list of levels, ranges,
range intervals or combination of the previous
"""
# it can be z=value1,value2,value3: z=2,10,80
# or z=minimum value/maximum value: z=10/100
# or z=Rn/min height/height interval: z=R20/100/50
try:
split_on_slash = z.split("/")
if len(split_on_slash) == 2:
z_min = convert_m_to_cm(split_on_slash[0]) if split_on_slash[0] != ".." else -sys.maxsize - 1
z_max = convert_m_to_cm(split_on_slash[1]) if split_on_slash[1] != ".." else sys.maxsize
return [f"{z_min}/{z_max}"]
elif len(split_on_slash) > 2:
return get_z_values_from_interval(split_on_slash)
else:
return [convert_m_to_cm(level) for level in z.split(",")]
except ValueError:
raise HTTPException(status_code=400, detail=f"Invalid levels value: {z}")
# or a combination of the above: z=10,30/100,200,300,R20/100/50

def get_level_or_range(z: str) -> list[str]:
try:
split_on_slash = z.split("/")
if len(split_on_slash) == 2:
return get_z_values_from_range(split_on_slash)
elif len(split_on_slash) > 2:
return get_z_values_from_interval(split_on_slash)
else:
return [convert_m_to_cm(z)]
except ValueError:
raise HTTPException(status_code=400, detail=f"Invalid levels value: {z}")

return list(chain(*[get_level_or_range(z) for z in split_and_strip(levels)]))


def get_z_values_from_range(range: list[str]) -> list[str]:
"""
Function for getting the z values from a range.
"""
start, end = range[0], range[1]
z_min = convert_m_to_cm(start) if start != ".." else start
z_max = convert_m_to_cm(end) if end != ".." else end

return [f"{z_min}/{z_max}"]


def get_z_values_from_interval(interval: list[str]) -> list[str]:
Expand Down

3 comments on commit 939cfd0

@github-actions
Copy link

Choose a reason for hiding this comment

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

Coverage

Unit Test Coverage Report
FileStmtsMissCoverMissing
__init__.py00100% 
datastore_pb2.py614821%34–81
datastore_pb2_grpc.py542750%15–16, 19, 65–80, 121–123, 128–130, 135–137, 142–144, 148–173, 219, 246, 273, 300
export_metrics.py100100% 
grpc_getter.py201145%15–19, 23–26, 30–32, 36–38
locustfile.py15150%1–31
main.py43784%45, 50, 60, 70–71, 81–82
metadata_endpoints.py663252%45–54, 58, 85, 100–220, 224
response_classes.py50100% 
utilities.py1803978%21, 39, 46, 68–71, 79–90, 95–102, 122, 126, 128, 156, 162, 180, 238–244, 248–250, 280, 284, 306, 311
custom_geo_json
   edr_feature_collection.py60100% 
formatters
   __init__.py110100% 
   covjson.py60198%91
   geojson.py21290%27, 52
openapi
   custom_dimension_examples.py40100% 
   edr_query_parameter_descriptions.py110100% 
   openapi_examples.py130100% 
routers
   __init__.py00100% 
   edr.py101496%348–349, 438–439
   feature.py471960%99–132, 148–153, 159–181
TOTAL72820572% 

Title Coverage Tests Skipped Failures Errors Time
API Unit Tests Coverage 40 0 💤 0 ❌ 0 🔥 1.852s ⏱️
Ingest Unit Tests Coverage 16 0 💤 0 ❌ 0 🔥 11.683s ⏱️

@github-actions
Copy link

Choose a reason for hiding this comment

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

Coverage

Unit Test Coverage Report
FileStmtsMissCoverMissing
__init__.py00100% 
datastore_pb2.py614821%34–81
datastore_pb2_grpc.py542750%15–16, 19, 65–80, 121–123, 128–130, 135–137, 142–144, 148–173, 219, 246, 273, 300
export_metrics.py100100% 
grpc_getter.py201145%15–19, 23–26, 30–32, 36–38
locustfile.py15150%1–31
main.py43784%45, 50, 60, 70–71, 81–82
metadata_endpoints.py663252%45–54, 58, 85, 100–220, 224
response_classes.py50100% 
utilities.py1803978%21, 39, 46, 68–71, 79–90, 95–102, 122, 126, 128, 156, 162, 180, 238–244, 248–250, 280, 284, 306, 311
custom_geo_json
   edr_feature_collection.py60100% 
formatters
   __init__.py110100% 
   covjson.py60198%91
   geojson.py21290%27, 52
openapi
   custom_dimension_examples.py40100% 
   edr_query_parameter_descriptions.py110100% 
   openapi_examples.py130100% 
routers
   __init__.py00100% 
   edr.py101496%348–349, 438–439
   feature.py471960%99–132, 148–153, 159–181
TOTAL72820572% 

Title Coverage Tests Skipped Failures Errors Time
API Unit Tests Coverage 40 0 💤 0 ❌ 0 🔥 1.892s ⏱️
Ingest Unit Tests Coverage 16 0 💤 0 ❌ 0 🔥 11.586s ⏱️

@github-actions
Copy link

Choose a reason for hiding this comment

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

Coverage

Unit Test Coverage Report
FileStmtsMissCoverMissing
__init__.py00100% 
datastore_pb2.py614821%34–81
datastore_pb2_grpc.py542750%15–16, 19, 65–80, 121–123, 128–130, 135–137, 142–144, 148–173, 219, 246, 273, 300
export_metrics.py100100% 
grpc_getter.py201145%15–19, 23–26, 30–32, 36–38
locustfile.py15150%1–31
main.py43784%45, 50, 60, 70–71, 81–82
metadata_endpoints.py663252%45–54, 58, 85, 100–220, 224
response_classes.py50100% 
utilities.py1803978%21, 39, 46, 68–71, 79–90, 95–102, 122, 126, 128, 156, 162, 180, 238–244, 248–250, 280, 284, 306, 311
custom_geo_json
   edr_feature_collection.py60100% 
formatters
   __init__.py110100% 
   covjson.py60198%91
   geojson.py21290%27, 52
openapi
   custom_dimension_examples.py40100% 
   edr_query_parameter_descriptions.py110100% 
   openapi_examples.py130100% 
routers
   __init__.py00100% 
   edr.py101496%348–349, 438–439
   feature.py471960%99–132, 148–153, 159–181
TOTAL72820572% 

Title Coverage Tests Skipped Failures Errors Time
API Unit Tests Coverage 40 0 💤 0 ❌ 0 🔥 1.903s ⏱️
Ingest Unit Tests Coverage 16 0 💤 0 ❌ 0 🔥 11.766s ⏱️

Please sign in to comment.