Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor to create a more maintainable structure #16

Merged
merged 13 commits into from
Jul 11, 2023
Merged
15 changes: 7 additions & 8 deletions cads_adaptors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,13 @@
# Local copy or not installed with setuptools
__version__ = "999"

from .adaptor import AbstractAdaptor, DummyAdaptor
from .adaptor_cds import (
AbstractCdsAdaptor,
DirectMarsCdsAdaptor,
LegacyCdsAdaptor,
MarsCdsAdaptor,
UrlCdsAdaptor,
)
from cads_adaptors.adaptors import AbstractAdaptor, DummyAdaptor

from cads_adaptors.adaptors.cds import AbstractCdsAdaptor
from cads_adaptors.adaptors.url import UrlCdsAdaptor
from cads_adaptors.adaptors.mars import MarsCdsAdaptor, DirectMarsCdsAdaptor
from cads_adaptors.adaptors.legacy import LegacyCdsAdaptor

from .tools.adaptor_tools import get_adaptor_class

__all__ = [
Expand Down
99 changes: 0 additions & 99 deletions cads_adaptors/adaptor_cds.py

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import abc
from typing import Any, BinaryIO

from cads_adaptors import constraints, costing
Copy link
Contributor

Choose a reason for hiding this comment

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

This is no longer needed



Request = dict[str, Any]


Expand Down
28 changes: 28 additions & 0 deletions cads_adaptors/adaptors/cds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from typing import Any

from cads_adaptors import constraints, costing
from cads_adaptors.adaptors import AbstractAdaptor, Request


class AbstractCdsAdaptor(AbstractAdaptor):
resources = {"CADS_ADAPTORS": 1}

def __init__(self, form: dict[str, Any], **config: Any):
self.form = form
self.constraints = config.pop("constraints", [])
self.mapping = config.pop("mapping", {})
self.licences: list[tuple[str, int]] = config.pop("licences", [])
self.config = config

def validate(self, request: Request) -> bool:
return True

def apply_constraints(self, request: Request) -> dict[str, Any]:
return constraints.validate_constraints(self.form, request, self.constraints)

def estimate_costs(self, request: Request) -> dict[str, int]:
costs = {"size": costing.estimate_size(self.form, request, self.constraints)}
return costs

def get_licences(self, request: Request) -> list[tuple[str, int]]:
return self.licences
18 changes: 18 additions & 0 deletions cads_adaptors/adaptors/legacy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

from typing import BinaryIO

from cads_adaptors.adaptors import cds, Request

class LegacyCdsAdaptor(cds.AbstractCdsAdaptor):
def retrieve(self, request: Request) -> BinaryIO:
import cdsapi

# parse input options
collection_id = self.config.pop("collection_id", None)
if not collection_id:
raise ValueError("collection_id is required in request")

# retrieve data
client = cdsapi.Client(self.config["url"], self.config["key"], retry_max=1)
result_path = client.retrieve(collection_id, request).download()
return open(result_path, "rb")
41 changes: 41 additions & 0 deletions cads_adaptors/adaptors/mars.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

import os
from typing import BinaryIO

from cads_adaptors import mapping
from cads_adaptors.adaptors import cds, Request


class DirectMarsAdaptor(cds.AbstractCdsAdaptor):
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
class DirectMarsAdaptor(cds.AbstractCdsAdaptor):
class DirectMarsCdsAdaptor(cds.AbstractCdsAdaptor):

resources = {"MARS_CLIENT": 1}

def retrieve(self, request: Request) -> BinaryIO:
import subprocess

with open("r", "w") as fp:
print("retrieve, target=data.grib", file=fp)
for key, value in request.items():
if not isinstance(value, (list, tuple)):
value = [value]
print(f", {key}={'/'.join(str(v) for v in value)}", file=fp)

env = dict(**os.environ)
# FIXME: set with the namespace and user_id
namespace = "cads"
user_id = 0
env["MARS_USER"] = f"{namespace}-{user_id}"

subprocess.run(["/usr/local/bin/mars", "r"], check=True, env=env)

return open("data.grib") # type: ignore


class MarsAdaptor(cds.AbstractCdsAdaptor):
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
class MarsAdaptor(cds.AbstractCdsAdaptor):
class MarsCdsAdaptor(cds.AbstractCdsAdaptor):

def retrieve(self, request: Request) -> BinaryIO:
format = request.pop("format", "grib")

mapped_request = mapping.apply_mapping(request, self.mapping) # type: ignore
if format != "grib":
# FIXME: reformat if needed
pass
return super().retrieve(mapped_request)
26 changes: 26 additions & 0 deletions cads_adaptors/adaptors/url.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

from typing import BinaryIO

from cads_adaptors import mapping
from cads_adaptors.adaptors import cds, Request


class UrlAdaptor(cds.AbstractCdsAdaptor):
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
class UrlAdaptor(cds.AbstractCdsAdaptor):
class UrlCdsAdaptor(cds.AbstractCdsAdaptor):

def retrieve(self, request: Request) -> BinaryIO:
from cads_adaptors.tools import url_tools

data_format = request.pop("format", "zip")

if data_format not in {"zip", "tgz"}:
raise ValueError(f"{data_format=} is not supported")

mapped_request = mapping.apply_mapping(request, self.mapping) # type: ignore

requests_urls = url_tools.requests_to_urls(
mapped_request, patterns=self.config["patterns"]
)

path = url_tools.download_from_urls(
[ru["url"] for ru in requests_urls], data_format=data_format
)
return open(path, "rb")
8 changes: 4 additions & 4 deletions cads_adaptors/tools/adaptor_tools.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from typing import Any

from .. import adaptor
from cads_adaptors.adaptors import AbstractAdaptor


def get_adaptor_class(
entry_point: str, setup_code: str | None = None
) -> type[adaptor.AbstractAdaptor]:
) -> type[AbstractAdaptor]:
from cacholote import decode

try:
Expand All @@ -17,8 +17,8 @@ def get_adaptor_class(
raise TypeError
exec(setup_code)
adaptor_class = eval(entry_point)
if not issubclass(adaptor_class, adaptor.AbstractAdaptor):
raise TypeError(f"{adaptor_class!r} is not subclass of AbstractAdaptor")
if not issubclass(adaptor_class, AbstractAdaptor):
raise TypeError(f"{adaptor_class!r} is not subclass of Base")
Copy link
Contributor

Choose a reason for hiding this comment

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

This line needs to be reverted:

Suggested change
raise TypeError(f"{adaptor_class!r} is not subclass of Base")
raise TypeError(f"{adaptor_class!r} is not subclass of AbstractAdaptor")

return adaptor_class # type: ignore


Expand Down