diff --git a/algorithm_catalog/worldcereal.json b/algorithm_catalog/worldcereal_inference.json similarity index 98% rename from algorithm_catalog/worldcereal.json rename to algorithm_catalog/worldcereal_inference.json index ef0f51a..55fa17a 100644 --- a/algorithm_catalog/worldcereal.json +++ b/algorithm_catalog/worldcereal_inference.json @@ -1,5 +1,5 @@ { - "id": "worldcereal_maize", + "id": "worldcereal_inference", "type": "Feature", "conformsTo": [ "http://www.opengis.net/spec/ogcapi-records-1/1.0/req/record-core" diff --git a/qa/tools/apex_algorithm_qa_tools/__init__.py b/qa/tools/apex_algorithm_qa_tools/__init__.py index f102a9c..7aca9c2 100644 --- a/qa/tools/apex_algorithm_qa_tools/__init__.py +++ b/qa/tools/apex_algorithm_qa_tools/__init__.py @@ -1 +1,4 @@ +# TODO: Flatten apex_algorithm_qa_tools to a single module and push as much functionality to https://github.com/ESA-APEx/esa-apex-toolbox-python + + __version__ = "0.0.1" diff --git a/qa/tools/apex_algorithm_qa_tools/common.py b/qa/tools/apex_algorithm_qa_tools/common.py new file mode 100644 index 0000000..3216263 --- /dev/null +++ b/qa/tools/apex_algorithm_qa_tools/common.py @@ -0,0 +1,35 @@ +from __future__ import annotations + +import logging +from pathlib import Path +from typing import Iterator + +# TODO: Flatten apex_algorithm_qa_tools to a single module and push as much functionality to https://github.com/ESA-APEx/esa-apex-toolbox-python + + +_log = logging.getLogger(__name__) + + +def get_project_root() -> Path: + """Try to find project root for common project use cases.""" + + def candidates() -> Iterator[Path]: + # TODO: support a environment variable to override the project root detection? + # Running from project root? + yield Path.cwd() + + # Running from qa/tools, qa/benchmarks, qa/unittests? + yield Path.cwd().parent.parent + + # Search from current file + yield Path(__file__).parent.parent.parent.parent + + for candidate in candidates(): + if candidate.is_dir() and all( + (candidate / p).is_dir() + for p in ["algorithm_catalog", "algorithm_invocations", "qa/tools"] + ): + _log.info(f"Detected project root {candidate!r}") + return candidate + + raise RuntimeError("Could not determine algorithm invocations root directory.") diff --git a/qa/tools/apex_algorithm_qa_tools/usecases.py b/qa/tools/apex_algorithm_qa_tools/usecases.py index e639a5d..7c19c0b 100644 --- a/qa/tools/apex_algorithm_qa_tools/usecases.py +++ b/qa/tools/apex_algorithm_qa_tools/usecases.py @@ -3,16 +3,16 @@ import dataclasses import json import logging -import os import re -from pathlib import Path from typing import List import requests +from apex_algorithm_qa_tools.common import get_project_root _log = logging.getLogger(__name__) +# TODO: Flatten apex_algorithm_qa_tools to a single module and push as much functionality to https://github.com/ESA-APEx/esa-apex-toolbox-python # TODO: rename `algorithm_invocations` and `qa/tools/apex_algorithm_qa_tools/usecases.py` to more descriptive "scenarios" or "benchmark-scenarios"? @@ -36,46 +36,11 @@ def from_dict(cls, data: dict) -> UseCase: ) -APEX_ALGORITHM_INVOCATIONS_ROOT = "APEX_ALGORITHM_INVOCATIONS_ROOT" - - -def get_algorithm_invocation_root() -> Path: - # TODO: find a better name for "algorithm invocations"? - # First attempt: check environment variable - if APEX_ALGORITHM_INVOCATIONS_ROOT in os.environ: - algo_root = os.environ[APEX_ALGORITHM_INVOCATIONS_ROOT] - _log.info( - f"Using algorithm invocations root {algo_root!r} (from environment variable {APEX_ALGORITHM_INVOCATIONS_ROOT})" - ) - return Path(algo_root) - - # Next attempts: try to detect project root - for project_root_candidate in [ - # Running from project root? - Path.cwd(), - # Running from qa/tools, qa/benchmarks, qa/unittests? - Path.cwd().parent.parent, - # Search from current file - Path(__file__).parent.parent.parent.parent, - ]: - if project_root_candidate.is_dir() and all( - (project_root_candidate / p).is_dir() - for p in ["algorithm_invocations", "qa/tools"] - ): - algo_root = project_root_candidate / "algorithm_invocations" - _log.info( - f"Using algorithm invocations root {algo_root!r} (assuming project root {project_root_candidate!r})" - ) - return algo_root - - raise RuntimeError("Could not determine algorithm invocations root directory.") - - def get_use_cases() -> List[UseCase]: # TODO: instead of flat list, keep original grouping/structure of "algorithm_invocations" files? # TODO: check for uniqueness of scenario IDs? Also make this a pre-commit lint tool? use_cases = [] - for path in get_algorithm_invocation_root().glob("*.json"): + for path in (get_project_root() / "algorithm_invocations").glob("**/*.json"): with open(path) as f: data = json.load(f) # TODO: support single use case files in addition to listings? diff --git a/qa/unittests/tests/test_algorithm_catalog.py b/qa/unittests/tests/test_algorithm_catalog.py new file mode 100644 index 0000000..84b375c --- /dev/null +++ b/qa/unittests/tests/test_algorithm_catalog.py @@ -0,0 +1,23 @@ +import json + +import pytest +from apex_algorithm_qa_tools.common import get_project_root + + +@pytest.mark.parametrize( + "path", list((get_project_root() / "algorithm_catalog").glob("**/*.json")) +) +def test_lint_algorithm_catalog_json_file(path): + data = json.loads(path.read_text()) + + assert data["id"] == path.stem + assert data["type"] == "Feature" + assert ( + "http://www.opengis.net/spec/ogcapi-records-1/1.0/req/record-core" + in data["conformsTo"] + ) + + assert data["properties"]["type"] == "apex_algorithm" + + assert "udp" in {k["rel"] for k in data["links"]} + # TODO more checks diff --git a/qa/unittests/tests/test_common.py b/qa/unittests/tests/test_common.py new file mode 100644 index 0000000..d6ad7a7 --- /dev/null +++ b/qa/unittests/tests/test_common.py @@ -0,0 +1,5 @@ +from apex_algorithm_qa_tools.common import get_project_root + + +def test_get_project_root(): + assert get_project_root().is_dir() diff --git a/qa/unittests/tests/test_openeo_udp.py b/qa/unittests/tests/test_openeo_udp.py new file mode 100644 index 0000000..0850eb4 --- /dev/null +++ b/qa/unittests/tests/test_openeo_udp.py @@ -0,0 +1,17 @@ +import json + +import pytest +from apex_algorithm_qa_tools.common import get_project_root + + +@pytest.mark.parametrize( + "path", list((get_project_root() / "openeo_udp").glob("**/*.json")) +) +def test_lint_openeo_udp_json_file(path): + data = json.loads(path.read_text()) + + assert data["id"] == path.stem + assert "description" in data + assert "parameters" in data + assert "process_graph" in data + # TODO more checks diff --git a/qa/unittests/tests/test_usecases.py b/qa/unittests/tests/test_usecases.py index 5492a18..203bb04 100644 --- a/qa/unittests/tests/test_usecases.py +++ b/qa/unittests/tests/test_usecases.py @@ -1,14 +1,5 @@ import pytest -from apex_algorithm_qa_tools.usecases import ( - UseCase, - get_algorithm_invocation_root, - get_use_cases, - lint_usecase, -) - - -def test_get_algorithm_invocation_root(): - assert get_algorithm_invocation_root().is_dir() +from apex_algorithm_qa_tools.usecases import UseCase, get_use_cases, lint_usecase def test_get_use_cases():