Skip to content

Commit

Permalink
refactor settings structure and accept reformatting
Browse files Browse the repository at this point in the history
  • Loading branch information
SerRichard committed Feb 21, 2024
1 parent 22d655a commit a2f6fa9
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 270 deletions.
10 changes: 4 additions & 6 deletions openeo_fastapi/api/app.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
from typing import Type

import attr
from attrs import Factory, define, field
from fastapi import APIRouter, FastAPI, Response
from attrs import define, field
from fastapi import APIRouter, Response
from starlette.responses import JSONResponse

from openeo_fastapi.client import models
Expand All @@ -12,8 +10,8 @@
class OpenEOApi:
"""Factory for creating FastApi applications conformant to the OpenEO Api specification."""

client: field()
app: field(default=Factory(lambda self: FastAPI))
client: field
app: field
router: APIRouter = attr.ib(default=attr.Factory(APIRouter))
response_class: type[Response] = attr.ib(default=JSONResponse)

Expand Down
117 changes: 59 additions & 58 deletions openeo_fastapi/client/collections.py
Original file line number Diff line number Diff line change
@@ -1,69 +1,70 @@
import aiohttp
from fastapi import APIRouter

from openeo_fastapi.client.models import Collection, Collections
from openeo_fastapi.client.settings import app_settings
from openeo_fastapi.client.settings import AppSettings

router_collections = APIRouter()

class CollectionCore:
def __init__(self, settings) -> None:
self.settings: AppSettings = settings
pass

async def get_collections():
"""
Returns Basic metadata for all datasets
"""
stac_url = (
app_settings.STAC_API_URL
if app_settings.STAC_API_URL.endswith("/")
else app_settings.STAC_API_URL + "/"
)
async def get_collections(self):
"""
Returns Basic metadata for all datasets
"""
stac_url = (
self.settings.STAC_API_URL
if self.settings.STAC_API_URL.endswith("/")
else self.settings.STAC_API_URL + "/"
)

try:
async with aiohttp.ClientSession() as client:
async with client.get(stac_url + "collections") as response:
resp = await response.json()
if response.status == 200 and resp.get("collections"):
collections_list = []
for collection_json in resp["collections"]:
if (
not app_settings.STAC_COLLECTIONS_WHITELIST
or collection_json["id"]
in app_settings.STAC_COLLECTIONS_WHITELIST
):
collections_list.append(collection_json)

return Collections(
collections=collections_list, links=resp["links"]
)
else:
return {"Error": "No Collections found."}
except Exception as e:
raise Exception("Ran into: ", e)
try:
async with aiohttp.ClientSession() as client:
async with client.get(stac_url + "collections") as response:
resp = await response.json()
if response.status == 200 and resp.get("collections"):
collections_list = []
for collection_json in resp["collections"]:
if (
not self.settings.STAC_COLLECTIONS_WHITELIST
or collection_json["id"]
in self.settings.STAC_COLLECTIONS_WHITELIST
):
collections_list.append(collection_json)

return Collections(
collections=collections_list, links=resp["links"]
)
else:
return {"Error": "No Collections found."}
except Exception as e:
raise Exception("Ran into: ", e)

async def get_collection(collection_id):
"""
Returns Metadata for specific datasetsbased on collection_id (str).
"""
stac_url = (
app_settings.STAC_API_URL
if app_settings.STAC_API_URL.endswith("/")
else app_settings.STAC_API_URL + "/"
)
async def get_collection(self, collection_id):
"""
Returns Metadata for specific datasetsbased on collection_id (str).
"""
stac_url = (
self.settings.STAC_API_URL
if self.settings.STAC_API_URL.endswith("/")
else self.settings.STAC_API_URL + "/"
)

try:
async with aiohttp.ClientSession() as client:
async with client.get(
stac_url + f"collections/{collection_id}"
) as response:
resp = await response.json()
if response.status == 200 and resp.get("id"):
if (
not app_settings.STAC_COLLECTIONS_WHITELIST
or resp["id"] in app_settings.STAC_COLLECTIONS_WHITELIST
):
return Collection(**resp)
else:
return {"Error": "Collection not found."}
try:
async with aiohttp.ClientSession() as client:
async with client.get(
stac_url + f"collections/{collection_id}"
) as response:
resp = await response.json()
if response.status == 200 and resp.get("id"):
if (
not self.settings.STAC_COLLECTIONS_WHITELIST
or resp["id"] in self.settings.STAC_COLLECTIONS_WHITELIST
):
return Collection(**resp)
else:
return {"Error": "Collection not found."}

except Exception as e:
raise Exception("Ran into: ", e)
except Exception as e:
raise Exception("Ran into: ", e)
57 changes: 25 additions & 32 deletions openeo_fastapi/client/core.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,35 @@
import abc

from attrs import define, field

from openeo_fastapi.client import conformance, models
from openeo_fastapi.client.collections import get_collection, get_collections
from openeo_fastapi.client.processes import list_processes

from collections import namedtuple
from urllib.parse import urlunparse

from attrs import define, field



from openeo_fastapi.client import conformance, models
from openeo_fastapi.client.collections import CollectionCore
from openeo_fastapi.client.processes import ProcessCore
from openeo_fastapi.client.settings import AppSettings


@define
class OpenEOCore:
"""Base client for the OpenEO Api."""

# TODO. Improve. Not quite sure about setting these here.

api_dns: str = field()
backend_version: str = field()
billing: str = field()
endpoints: list = field()
links: list = field()
api_tls: bool = field(default=True)

settings: AppSettings = field()

_id: str = field(default="OpenEOApi")
title: str = field(default="OpenEO FastApi")
description: str = field(default="Implemented from the OpenEO FastAPi package.")
stac_version: str = field(default="1.0.0")
api_version: str = field(default="1.1.0")

_collections = CollectionCore(settings)
_processes = ProcessCore()

@abc.abstractmethod
def get_well_know(self) -> models.WellKnownOpeneoGetResponse:
""" """

prefix = "https" if self.api_tls else "http"
prefix = "https" if self.settings.API_TLS else "http"

Components = namedtuple(
typename="Components",
Expand All @@ -47,17 +40,19 @@ def get_well_know(self) -> models.WellKnownOpeneoGetResponse:
url = urlunparse(
Components(
scheme=prefix,
netloc=self.api_dns,
netloc=self.settings.API_DNS,
query=None,
path="",
url=f"/openeo/{self.api_version}/",
url=f"/openeo/{self.settings.OPENEO_VERSION}/",
fragment=None,
)
)

return models.WellKnownOpeneoGetResponse(
versions=[
models.Version(url=url, production=False, api_version=self.api_version)
models.Version(
url=url, production=False, api_version=self.settings.OPENEO_VERSION
)
]
)

Expand All @@ -66,30 +61,29 @@ def get_capabilities(self) -> models.Capabilities:
""" """
return models.Capabilities(
id=self._id,
title=self.title,
stac_version=self.stac_version,
api_version=self.api_version,
description=self.description,
backend_version=self.backend_version,
title=self.settings.API_TITLE,
stac_version=self.settings.STAC_VERSION,
api_version=self.settings.OPENEO_VERSION,
description=self.settings.API_DESCRIPTION,
backend_version=self.settings.OPENEO_VERSION,
billing=self.billing,
links=self.links,
endpoints=self.endpoints,
)


@abc.abstractclassmethod
async def get_collection(self, collection_id) -> models.Collection:
collection = await get_collection(collection_id)
collection = await self._collections.get_collection(collection_id)
return collection

@abc.abstractclassmethod
async def get_collections(self) -> models.Collections:
collections = await get_collections()
collections = await self._collections.get_collections()
return collections

@abc.abstractclassmethod
def get_processes(self) -> dict:
processes = list_processes()
processes = self._processes.list_processes()
return processes

@abc.abstractmethod
Expand All @@ -98,4 +92,3 @@ def get_conformance(self) -> models.ConformanceGetResponse:
return models.ConformanceGetResponse(
conformsTo=conformance.BASIC_CONFORMANCE_CLASSES
)

86 changes: 39 additions & 47 deletions openeo_fastapi/client/processes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,45 @@
from typing import Union

import openeo_pg_parser_networkx
import openeo_processes_dask
import openeo_processes_dask.specs
from fastapi import APIRouter
from openeo_pg_parser_networkx import ProcessRegistry

import openeo_fastapi
from openeo_fastapi.client.models import Error, Link, ProcessesGetResponse

router_processes = APIRouter()
process_registry = ProcessRegistry()

predefined_processes_specs = {
process_id: getattr(openeo_processes_dask.specs, process_id)
for process_id in openeo_processes_dask.specs.__all__
}

for process_id, spec in predefined_processes_specs.items():
process_registry[("predefined", process_id)] = openeo_pg_parser_networkx.Process(
spec
)


@functools.cache
def get_available_processes():
return [
openeo_fastapi.client.models.Process.parse_obj(process.spec)
for process in process_registry["predefined", None].values()
]


def list_processes() -> Union[ProcessesGetResponse, Error]:
"""
Returns Supported predefined processes defined by openeo-processes-dask
"""
try:
processes = get_available_processes()
resp = ProcessesGetResponse(
processes=processes,
links=[
Link(
href="https://eodc.eu/",
rel="about",
type="text/html",
title="Homepage of the service provider",
)
],
)
return resp
except Exception as e:
raise Exception(f"Error while getting available Processes: {e}")
from openeo_fastapi.client.models import Error, Process, ProcessesGetResponse


class ProcessCore:
def __init__(self) -> None:
self.process_registry = ProcessRegistry()

predefined_processes_specs = {
process_id: getattr(openeo_processes_dask.specs, process_id)
for process_id in openeo_processes_dask.specs.__all__
}

for process_id, spec in predefined_processes_specs.items():
self.process_registry[
("predefined", process_id)
] = openeo_pg_parser_networkx.Process(spec)

pass

@functools.cache
def get_available_processes(self):
return [
Process.parse_obj(process.spec)
for process in self.process_registry["predefined", None].values()
]

def list_processes(self) -> Union[ProcessesGetResponse, Error]:
"""
Returns Supported predefined processes defined by openeo-processes-dask
"""
try:
processes = self.get_available_processes()
resp = ProcessesGetResponse(
processes=processes,
links=[],
)
return resp
except Exception as e:
raise Exception(f"Error while getting available Processes: {e}")
17 changes: 11 additions & 6 deletions openeo_fastapi/client/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,23 @@
class AppSettings(BaseSettings):
"""Place to store application settings."""

OPENEO_VERSION = "1.1.0"
API_DNS = HttpUrl
API_TLS: str = "True"

API_TITLE: str
API_DESCRIPTION: str

OPENEO_VERSION: str = "1.1.0"
OPENEO_PREFIX = f"/{OPENEO_VERSION}"

# External APIs
STAC_API_URL: Optional[HttpUrl] = "http://test-stac-api.mock.com/api"
STAC_COLLECTIONS_WHITELIST: list[str] = []
STAC_VERSION: str = "1.0.0"
STAC_API_URL: Optional[HttpUrl]
STAC_COLLECTIONS_WHITELIST: Optional[list[str]] = []

class Config:
@classmethod
def parse_env_var(cls, field_name: str, raw_val: str) -> Any:
if field_name == "STAC_COLLECTIONS_WHITELIST":
return [x for x in raw_val.split(",")]
return cls.json_loads(raw_val)


app_settings = AppSettings()
Loading

0 comments on commit a2f6fa9

Please sign in to comment.