Skip to content
This repository has been archived by the owner on Nov 19, 2024. It is now read-only.

Add remote datetimes #95

Merged
merged 4 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 10 additions & 15 deletions cads_api_client/catalogue.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,33 +32,28 @@ class Collection(ApiResponse):
"""A class to interact with a catalogue collection."""

@property
def _temporal_interval(self) -> tuple[str, str]:
begin, end = map(str, self.json["extent"]["temporal"]["interval"][0])
return (begin, end)

@property
def begin_datetime(self) -> datetime.datetime:
def begin_datetime(self) -> datetime.datetime | None:
"""Begin datetime of the collection.

Returns
-------
datetime.datetime
datetime.datetime or None
"""
return datetime.datetime.fromisoformat(
self._temporal_interval[0].replace("Z", "+00:00")
)
if (value := self.json["extent"]["temporal"]["interval"][0][0]) is None:
return value
return datetime.datetime.fromisoformat(value.replace("Z", "+00:00"))

@property
def end_datetime(self) -> datetime.datetime:
def end_datetime(self) -> datetime.datetime | None:
"""End datetime of the collection.

Returns
-------
datetime.datetime
datetime.datetime or None
"""
return datetime.datetime.fromisoformat(
self._temporal_interval[1].replace("Z", "+00:00")
)
if (value := self.json["extent"]["temporal"]["interval"][0][1]) is None:
return value
return datetime.datetime.fromisoformat(value.replace("Z", "+00:00"))

@property
def bbox(self) -> tuple[float, float, float, float]:
Expand Down
36 changes: 34 additions & 2 deletions cads_api_client/processing.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import datetime
import functools
import logging
import os
Expand Down Expand Up @@ -447,8 +448,39 @@ def status(self) -> str:
"""
reply = self.json
self._log_metadata(reply.get("metadata", {}))
status: str = reply["status"]
return status
return str(reply["status"])

@property
def creation_datetime(self) -> datetime.datetime:
"""Creation datetime of the job.

Returns
-------
datetime.datetime
"""
return datetime.datetime.fromisoformat(self.json["created"])

@property
def start_datetime(self) -> datetime.datetime | None:
"""Start datetime of the job. If None, job has not started.

Returns
-------
datetime.datetime or None
"""
value = self.json.get("started")
return value if value is None else datetime.datetime.fromisoformat(value)

@property
def end_datetime(self) -> datetime.datetime | None:
"""End datetime of the job. If None, job has not finished.

Returns
-------
datetime.datetime or None
"""
value = self.json.get("finished")
return value if value is None else datetime.datetime.fromisoformat(value)

def _wait_on_results(self) -> None:
sleep = 1.0
Expand Down
2 changes: 2 additions & 0 deletions tests/integration_test_10_catalogue.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@ def test_catalogue_collection_submit(collection: Collection) -> None:


def test_catalogue_collection_begin_datetime(collection: Collection) -> None:
assert collection.begin_datetime is not None
assert collection.begin_datetime.isoformat() == "1959-01-01T00:00:00+00:00"


def test_catalogue_collection_end_datetime(collection: Collection) -> None:
assert collection.end_datetime is not None
assert collection.end_datetime.isoformat() == "2023-05-09T00:00:00+00:00"


Expand Down
16 changes: 16 additions & 0 deletions tests/integration_test_30_remote.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import contextlib
import datetime
import os
import pathlib
import uuid
Expand Down Expand Up @@ -86,3 +87,18 @@ def test_remote_cleanup(
client = ApiClient(url=api_root_url, key=api_anon_key, maximum_tries=0)
with raises:
client.get_remote(request_uid)


def test_remote_datetimes(api_anon_client: ApiClient) -> None:
remote = api_anon_client.submit(
"test-adaptor-dummy",
elapsed=1,
_timestamp=datetime.datetime.now().isoformat(),
)
assert isinstance(remote.creation_datetime, datetime.datetime)
assert remote.end_datetime is None

remote.make_results()
assert remote.start_datetime is not None
assert remote.end_datetime is not None
assert remote.creation_datetime < remote.start_datetime < remote.end_datetime
46 changes: 12 additions & 34 deletions tests/test_10_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from cads_api_client import catalogue, processing

COLLECTION_ID = "reanalysis-era5-pressure-levels"
JOB_RUNNING_ID = "9bfc1362-2832-48e1-a235-359267420bb1"
JOB_SUCCESSFUL_ID = "9bfc1362-2832-48e1-a235-359267420bb2"
JOB_FAILED_ID = "9bfc1362-2832-48e1-a235-359267420bb3"

Expand All @@ -21,13 +20,9 @@
PROCESS_URL = f"http://localhost:8080/api/retrieve/v1/processes/{COLLECTION_ID}"
EXECUTE_URL = f"{PROCESS_URL}/execution"

JOB_RUNNING_URL = f"http://localhost:8080/api/retrieve/v1/jobs/{JOB_RUNNING_ID}"
JOB_SUCCESSFUL_URL = f"http://localhost:8080/api/retrieve/v1/jobs/{JOB_SUCCESSFUL_ID}"
JOB_FAILED_URL = f"http://localhost:8080/api/retrieve/v1/jobs/{JOB_FAILED_ID}"

RESULT_RUNNING_URL = (
f"http://localhost:8080/api/retrieve/v1/jobs/{JOB_RUNNING_ID}/results"
)
RESULT_SUCCESSFUL_URL = (
f"http://localhost:8080/api/retrieve/v1/jobs/{JOB_SUCCESSFUL_ID}/results"
)
Expand Down Expand Up @@ -178,28 +173,6 @@
},
}

JOB_RUNNING_JSON = {
"processID": f"{COLLECTION_ID}",
"type": "process",
"jobID": f"{JOB_RUNNING_ID}",
"status": "running",
"created": "2022-09-02T17:30:48.201213",
"updated": "2022-09-02T17:30:48.201217",
"links": [
{
"href": f"{COLLECTION_URL}/execution",
"rel": "self",
"type": "application/json",
},
{
"href": f"{JOB_RUNNING_URL}",
"rel": "monitor",
"type": "application/json",
"title": "job status info",
},
],
}


JOB_SUCCESSFUL_JSON = {
"processID": f"{COLLECTION_ID}",
Expand Down Expand Up @@ -279,13 +252,6 @@
}


RESULT_RUNNING_JSON = {
"type": "http://www.opengis.net/def/exceptions/ogcapi-processes-1/1.0/result-not-ready",
"title": "job results not ready",
"detail": "job 8b7a1f3d-04b1-425d-96f1-f0634d02ee7f results are not yet ready",
"instance": "http://127.0.0.1:8080/api/retrieve/v1/jobs/8b7a1f3d-04b1-425d-96f1-f0634d02ee7f/results",
}

RESULT_FAILED_JSON = {
"type": "job results failed",
"title": "job failed",
Expand Down Expand Up @@ -413,6 +379,12 @@ def test_submit(cat: catalogue.Catalogue) -> None:
assert remote.url == JOB_SUCCESSFUL_URL
assert remote.status == "successful"

assert remote.creation_datetime.isoformat() == "2022-09-02T17:30:48.201213"
assert remote.start_datetime is not None
assert remote.start_datetime.isoformat() == "2022-09-02T17:32:43.890617"
assert remote.end_datetime is not None
assert remote.end_datetime.isoformat() == "2022-09-02T17:32:54.308120"


@responses.activate
def test_wait_on_result(cat: catalogue.Catalogue) -> None:
Expand All @@ -435,6 +407,12 @@ def test_wait_on_result_failed(cat: catalogue.Catalogue) -> None:
):
remote._wait_on_results()

assert remote.creation_datetime.isoformat() == "2022-09-02T17:30:48.201213"
assert remote.start_datetime is not None
assert remote.start_datetime.isoformat() == "2022-09-02T17:32:43.890617"
assert remote.end_datetime is not None
assert remote.end_datetime.isoformat() == "2022-09-02T17:32:54.308120"


@responses.activate
def test_remote_logs(
Expand Down