Skip to content

Commit

Permalink
Merge pull request #125 from FREVA-CLINT/entrypoint-bugfixes
Browse files Browse the repository at this point in the history
Entrypoint bugfixes
  • Loading branch information
antarcticrainforest authored Feb 24, 2025
2 parents def2efa + fbc3904 commit 9d7213a
Show file tree
Hide file tree
Showing 17 changed files with 418 additions and 368 deletions.
2 changes: 1 addition & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fail_under = 95
exclude_lines =
# Have to re-enable the standard pragma
pragma: no cover

def __call__
# Don't complain about missing debug-only code:
def __repr__
if self\.debug
Expand Down
1 change: 1 addition & 0 deletions .github/README.md
1 change: 1 addition & 0 deletions .github/ghcr-readme
54 changes: 34 additions & 20 deletions .github/workflows/build_job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,35 @@ jobs:
release-type-determination:
name: Determine if tag is pre-released or not
runs-on: ubuntu-latest
outputs:
is_prerelease: ${{ steps.check-prerelease.outputs.is_prerelease }}
tag: ${{ steps.get-tag.outputs.tag }}
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Get tag
id: get-tag
run: |
echo "tag=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
echo "tag=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"
- name: Check if tag is a pre-release
id: check-prerelease
run: |
TAG="${{ steps.get-tag.outputs.tag }}"
if [[ "$TAG" == *"-dev"* || "$TAG" == *"-beta"* || "$TAG" == *"-alpha"* ]]; then
echo "This is a pre-release tag."
echo "is_prerelease=true" >> $GITHUB_OUTPUT
echo "ghcr.io/freva-clint/freva-rest-api-dev" > image.txt
else
echo "This is not a pre-release tag."
echo "is_prerelease=false" >> $GITHUB_OUTPUT
fi
echo "ghcr.io/freva-clint/freva-rest-api" > image.txt
fi
echo "${{ steps.get-tag.outputs.tag }}" > tag.txt
echo "${{ steps.check-prerelease.outputs.is_prerelease }}" > is_prerelease.txt
- name: Upload Outputs
uses: actions/upload-artifact@v4
with:
name: release-metadata
path: |
image.txt
tag.txt
is_prerelease.txt
tests:
uses: ./.github/workflows/ci_job.yml

Expand Down Expand Up @@ -91,14 +97,22 @@ jobs:
with:
submodules: recursive

- name: Set up Python 3
uses: actions/setup-python@v4
- name: Download Release Metadata
uses: actions/download-artifact@v4
with:
python-version: "3.X"
name: release-metadata

- name: Get tag
run: echo "tag=${{ needs.release-type-determination.outputs.tag }}" >> $GITHUB_OUTPUT
shell: bash
- name: Read Metadata
run: |
IMAGE=$(cat image.txt)
TAG=$(cat tag.txt)
IS_PRERELEASE=$(cat is_prerelease.txt)
echo "IMAGE=$IMAGE" >> $GITHUB_ENV
echo "TAG=$TAG" >> $GITHUB_ENV
echo "IS_PRERELEASE=$IS_PRERELEASE" >> $GITHUB_ENV
echo "DEBUG: IMAGE=$IMAGE"
echo "DEBUG: TAG=$TAG"
echo "DEBUG: IS_PRERELEASE=$IS_PRERELEASE"
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
Expand All @@ -118,13 +132,13 @@ jobs:
with:
context: freva-rest
file: freva-rest/Dockerfile
build-args: VERSION=${{ needs.release-type-determination.outputs.tag }}
platforms: linux/amd64, linux/arm64
build-args: VERSION=${{ env.TAG }}
platforms: linux/amd64, linux/arm64, linux/ppc64le
push: true
no-cache: true
tags: |
ghcr.io/freva-clint/freva-rest-api:${{ needs.release-type-determination.outputs.tag }}
ghcr.io/freva-clint/freva-rest-api:${{ needs.release-type-determination.outputs.is_prerelease == 'false' && 'latest' || needs.release-type-determination.outputs.tag }}
${{ env.IMAGE }}:${{ env.TAG }}
${{ env.IMAGE }}:${{ env.IS_PRERELEASE == 'false' && 'latest' || env.TAG }}
pypi:
name: Create Pip package
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci_job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ jobs:
platforms: linux/amd64
push: false
load: true
no-cache: true
tags: freva-rest:latest

- name: Waiting for keycloak
Expand Down
44 changes: 27 additions & 17 deletions freva-client/src/freva_client/cli/databrowser_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,27 +32,27 @@ def _auth(url: str, token: Optional[str]) -> None:
class UniqKeys(str, Enum):
"""Literal implementation for the cli."""

file: str = "file"
uri: str = "uri"
file = "file"
uri = "uri"


class Flavours(str, Enum):
"""Literal implementation for the cli."""

freva: str = "freva"
cmip6: str = "cmip6"
cmip5: str = "cmip5"
cordex: str = "cordex"
nextgems: str = "nextgems"
user: str = "user"
freva = "freva"
cmip6 = "cmip6"
cmip5 = "cmip5"
cordex = "cordex"
nextgems = "nextgems"
user = "user"


class TimeSelect(str, Enum):
"""Literal implementation for the cli."""

strict: str = "strict"
flexible: str = "flexible"
file: str = "file"
strict = "strict"
flexible = "flexible"
file = "file"

@staticmethod
def get_help() -> str:
Expand Down Expand Up @@ -188,7 +188,9 @@ def metadata_search(
result = databrowser.metadata_search(
*(facets or []),
time=time or "",
time_select=cast(Literal["file", "flexible", "strict"], time_select.value),
time_select=cast(
Literal["file", "flexible", "strict"], time_select.value
),
flavour=cast(
Literal["freva", "cmip6", "cmip5", "cordex", "nextgems", "user"],
flavour.value,
Expand Down Expand Up @@ -462,7 +464,9 @@ def intake_catalogue(
print(Path(temp_f.name).read_text())


@databrowser_app.command(name="data-count", help="Count the databrowser search results")
@databrowser_app.command(
name="data-count", help="Count the databrowser search results"
)
@exception_handler
def count_values(
search_keys: Optional[List[str]] = typer.Argument(
Expand Down Expand Up @@ -581,9 +585,13 @@ def count_values(
databrowser(
*facets,
time=time or "",
time_select=cast(Literal["file", "flexible", "strict"], time_select),
time_select=cast(
Literal["file", "flexible", "strict"], time_select
),
flavour=cast(
Literal["freva", "cmip6", "cmip5", "cordex", "nextgems", "user"],
Literal[
"freva", "cmip6", "cmip5", "cordex", "nextgems", "user"
],
flavour.value,
),
host=host,
Expand Down Expand Up @@ -663,11 +671,13 @@ def user_data_add(
action="add",
userdata_items=cast(List[Union[str, xr.Dataset]], paths),
metadata=facet_dict,
host=host
host=host,
)


@user_data_app.command(name="delete", help="Delete user data from the databrowser.")
@user_data_app.command(
name="delete", help="Delete user data from the databrowser."
)
@exception_handler
def user_data_delete(
search_keys: List[str] = typer.Option(
Expand Down
51 changes: 36 additions & 15 deletions freva-client/src/freva_client/query.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Query climate data sets by using-key value pair search queries."""


import sys
from collections import defaultdict
from fnmatch import fnmatch
Expand Down Expand Up @@ -246,7 +245,8 @@ def _add_search_keyword_args_from_facet(
self, facets: Tuple[str, ...], search_kw: Dict[str, List[str]]
) -> None:
metadata = {
k: v[::2] for (k, v) in self._facet_search(extended_search=True).items()
k: v[::2]
for (k, v) in self._facet_search(extended_search=True).items()
}
primary_key = list(metadata.keys() or ["project"])[0]
num_facets = 0
Expand Down Expand Up @@ -304,7 +304,9 @@ def _repr_html_(self) -> str:

# Create a table-like structure for available flavors and search facets
style = 'style="text-align: left"'
facet_heading = f"Available search facets for <em>{self._flavour}</em> flavour"
facet_heading = (
f"Available search facets for <em>{self._flavour}</em> flavour"
)
html_repr = (
"<table>"
f"<tr><th colspan='2' {style}>{self.__class__.__name__}"
Expand Down Expand Up @@ -345,7 +347,9 @@ def _create_intake_catalogue_file(self, filename: str) -> None:
if self._stream_zarr:
token = self._auth.check_authentication(auth_url=self._cfg.auth_url)
url = self._cfg.zarr_loader_url
kwargs["headers"] = {"Authorization": f"Bearer {token['access_token']}"}
kwargs["headers"] = {
"Authorization": f"Bearer {token['access_token']}"
}
kwargs["params"] = {"catalogue-type": "intake"}
result = self._request("GET", url, **kwargs)
if result is None:
Expand All @@ -357,7 +361,9 @@ def _create_intake_catalogue_file(self, filename: str) -> None:
for content in result.iter_content(decode_unicode=False):
stream.write(content)
except Exception as error:
raise ValueError(f"Couldn't write catalogue content: {error}") from None
raise ValueError(
f"Couldn't write catalogue content: {error}"
) from None

def intake_catalogue(self) -> intake_esm.core.esm_datastore:
"""Create an intake esm catalogue object from the search.
Expand Down Expand Up @@ -388,7 +394,10 @@ def intake_catalogue(self) -> intake_esm.core.esm_datastore:
"""
with NamedTemporaryFile(suffix=".json") as temp_f:
self._create_intake_catalogue_file(temp_f.name)
return intake.open_esm_datastore(temp_f.name)
return cast(
intake_esm.core.esm_datastore,
intake.open_esm_datastore(temp_f.name),
)

@classmethod
def count_values(
Expand Down Expand Up @@ -495,7 +504,9 @@ def count_values(
result = this._facet_search(extended_search=extended_search)
counts = {}
for facet, value_counts in result.items():
counts[facet] = dict(zip(value_counts[::2], map(int, value_counts[1::2])))
counts[facet] = dict(
zip(value_counts[::2], map(int, value_counts[1::2]))
)
return counts

@cached_property
Expand All @@ -520,7 +531,8 @@ def metadata(self) -> Dict[str, List[str]]:
"""
return {
k: v[::2] for (k, v) in self._facet_search(extended_search=True).items()
k: v[::2]
for (k, v) in self._facet_search(extended_search=True).items()
}

@classmethod
Expand Down Expand Up @@ -653,7 +665,9 @@ def metadata_search(
)
return {
k: v[::2]
for (k, v) in this._facet_search(extended_search=extended_search).items()
for (k, v) in this._facet_search(
extended_search=extended_search
).items()
}

@classmethod
Expand Down Expand Up @@ -856,24 +870,29 @@ def _request(
method: Literal["GET", "POST", "PUT", "PATCH", "DELETE"],
url: str,
data: Optional[Dict[str, Any]] = None,
**kwargs: Any
**kwargs: Any,
) -> Optional[requests.models.Response]:
"""Request method to handle CRUD operations (GET, POST, PUT, PATCH, DELETE)."""
method_upper = method.upper()
timeout = kwargs.pop("timeout", 30)
params = kwargs.pop("params", {})
stream = kwargs.pop("stream", False)

logger.debug("%s request to %s with data: %s and parameters: %s",
method_upper, url, data, {**self._params, **params})
logger.debug(
"%s request to %s with data: %s and parameters: %s",
method_upper,
url,
data,
{**self._params, **params},
)

try:
req = requests.Request(
method=method_upper,
url=url,
params={**self._params, **params},
json=None if method_upper in "GET" else data,
**kwargs
**kwargs,
)
with requests.Session() as session:
prepared = session.prepare_request(req)
Expand All @@ -883,8 +902,10 @@ def _request(

except KeyboardInterrupt:
pprint("[red][b]User interrupt: Exit[/red][/b]", file=sys.stderr)
except (requests.exceptions.ConnectionError,
requests.exceptions.HTTPError) as error:
except (
requests.exceptions.ConnectionError,
requests.exceptions.HTTPError,
) as error:
msg = f"{method_upper} request failed with {error}"
if self._fail_on_error:
raise ValueError(msg) from None
Expand Down
Loading

0 comments on commit 9d7213a

Please sign in to comment.