Skip to content
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
17 changes: 17 additions & 0 deletions src/gfwapiclient/resources/bulk_downloads/list/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""Global Fishing Watch (GFW) API Python Client - Get All Bulk Reports.

This module provides the endpoint and associated functionalities for retrieving details
of multiple previously created bulk reports. It defines the `BulkReportListEndPoint`
class, which handles the construction and execution of API requests, and the parsing
of API responses for Get All Bulk Reports API endpoint.

For detailed information about the Get All Bulk Reports API endpoint, please refer to
the official Global Fishing Watch API documentation:

See: https://globalfishingwatch.org/our-apis/documentation#get-all-bulk-reports-by-user

For more details on the Get All Bulk Reports data caveats, please refer to the
official Global Fishing Watch API documentation:

See: https://globalfishingwatch.org/our-apis/documentation#sar-fixed-infrastructure-data-caveats
"""
104 changes: 104 additions & 0 deletions src/gfwapiclient/resources/bulk_downloads/list/endpoints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
"""Global Fishing Watch (GFW) API Python Client - Get All Bulk Reports API endpoint."""

from typing import Any, Dict, List, Union

from typing_extensions import override

from gfwapiclient.exceptions.validation import ResultValidationError
from gfwapiclient.http.client import HTTPClient
from gfwapiclient.http.endpoints import GetEndPoint
from gfwapiclient.http.models import RequestBody
from gfwapiclient.resources.bulk_downloads.list.models.request import (
BulkReportListParams,
)
from gfwapiclient.resources.bulk_downloads.list.models.response import (
BulkReportListItem,
BulkReportListResult,
)


__all__ = ["BulkReportListEndPoint"]


class BulkReportListEndPoint(
GetEndPoint[
BulkReportListParams, RequestBody, BulkReportListItem, BulkReportListResult
],
):
"""Get All Bulk Reports API endpoint.

This endpoint retrieves a list of metadata and status of the previously created
bulk reports based on the provided request parameters.

For more details on the Get All Bulk Reports API endpoint, please refer to the
official Global Fishing Watch API documentation:

See: https://globalfishingwatch.org/our-apis/documentation#get-all-bulk-reports-by-user
"""

def __init__(
self,
*,
request_params: BulkReportListParams,
http_client: HTTPClient,
) -> None:
"""Initializes a new `BulkReportListEndPoint`.

Args:
request_params (BulkReportListParams):
The request parameters.

http_client (HTTPClient):
The HTTP client used to make the API call.
"""
super().__init__(
path="bulk-reports",
request_params=request_params,
result_item_class=BulkReportListItem,
result_class=BulkReportListResult,
http_client=http_client,
)

@override
def _transform_response_data(
self,
*,
body: Union[List[Dict[str, Any]], Dict[str, Any]],
) -> Union[List[Dict[str, Any]], Dict[str, Any]]:
"""Transform and reshape response body and yield data.

This method transforms the raw response body from the API into a format
suitable for the `BulkReportListResult` model.

The expected response structure is: `{"entries": [{...}]}`.

Args:
body (Union[List[Dict[str, Any]], Dict[str, Any]]):
The raw response body.

Returns:
Union[List[Dict[str, Any]], Dict[str, Any]]:
The transformed response data.

Raises:
ResultValidationError:
If the response body does not match the expected format.
"""
# expected: {"entries": [{"key": ...}, ...], ...}
if not isinstance(body, dict) or "entries" not in body:
raise ResultValidationError(
message="Expected a list of entries, but got an empty list.",
body=body,
)

# Transforming and reshaping entries
bulk_report_entries: List[Dict[str, Any]] = body.get("entries", [])
transformed_data: List[Dict[str, Any]] = []

# Loop through "entries" list i.e [{"key": ..., ...}, ...]
for bulk_report_entry in bulk_report_entries:
# Append extracted dictionaries, if not empty
if bulk_report_entry:
transformed_data.append(dict(**bulk_report_entry))

return transformed_data
17 changes: 17 additions & 0 deletions src/gfwapiclient/resources/bulk_downloads/list/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""Global Fishing Watch (GFW) API Python Client - Get All Bulk Reports Models.

This module defines Pydantic data models used for interacting with the
Get All Bulk Reports API endpoint. These models are used to represent
request parameters, and response data when retrieving detailed metadata and status of
multiple previously created bulk report

For detailed information about the Get All Bulk Reports API endpoint, please refer to
the official Global Fishing Watch API documentation:

See: https://globalfishingwatch.org/our-apis/documentation#get-all-bulk-reports-by-user

For more details on the Get All Bulk Reports data caveats, please refer to the
official Global Fishing Watch API documentation:

See: https://globalfishingwatch.org/our-apis/documentation#sar-fixed-infrastructure-data-caveats
"""
50 changes: 50 additions & 0 deletions src/gfwapiclient/resources/bulk_downloads/list/models/request.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Global Fishing Watch (GFW) API Python Client - Get All Bulk Reports Request Models."""

from typing import Final, Optional

from pydantic import Field

from gfwapiclient.http.models import RequestParams
from gfwapiclient.resources.bulk_downloads.base.models.response import BulkReportStatus


__all__ = ["BulkReportListParams"]


BULK_REPORT_LIST_PARAMS_VALIDATION_ERROR_MESSAGE: Final[str] = (
"Get bulk reports request parameters validation failed."
)


class BulkReportListParams(RequestParams):
"""Request query parameters for Get All Bulk Reports API endpoint.

Represents pagination, sorting, filtering parameters etc. for retrieving
previously created bulk reports.

For more details on the Get All Bulk Reports API endpoint supported
request parameters, please refer to the official Global Fishing Watch API
documentation:

See: https://globalfishingwatch.org/our-apis/documentation#get-all-bulk-reports-by-user

Attributes:
limit (Optional[int]):
Maximum number of bulk reports to return.
Defaults to `99999`.

offset (Optional[int]):
Number of bulk reports to skip before returning results.
Used for pagination. Defaults to `0`.

sort (Optional[str]):
Property to sort the bulk reports by (e.g., `"-createdAt"`).

status (Optional[BulkReportStatus]):
Current status of the bulk report generation process (e.g., `"done"` etc.).
"""

limit: Optional[int] = Field(99999, ge=0, alias="limit")
offset: Optional[int] = Field(0, ge=0, alias="offset")
sort: Optional[str] = Field("-createdAt", alias="sort")
status: Optional[BulkReportStatus] = Field(None, alias="status")
58 changes: 58 additions & 0 deletions src/gfwapiclient/resources/bulk_downloads/list/models/response.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""Global Fishing Watch (GFW) API Python Client - Get All Bulk Reports Response Models."""

from typing import List, Type

from gfwapiclient.http.models import Result
from gfwapiclient.resources.bulk_downloads.base.models.response import BulkReportItem


__all__ = ["BulkReportListItem", "BulkReportListResult"]


class BulkReportListItem(BulkReportItem):
"""Result item for the Get All Bulk Reports API endpoint.

Represents metadata and status of the previously created bulk report.

For more details on the Get All Bulk Reports API endpoint supported
response bodies, please refer to the official Global Fishing Watch API
documentation:

See: https://globalfishingwatch.org/our-apis/documentation#get-all-bulk-reports-by-user

See: https://globalfishingwatch.org/our-apis/documentation#bulk-reports-get-http-response

See: https://globalfishingwatch.org/our-apis/documentation#bulk-report-object-schema
"""

pass


class BulkReportListResult(Result[BulkReportListItem]):
"""Result for the Get All Bulk Reports API endpoint.

For more details on the Get All Bulk Reports API endpoint supported
response bodies, please refer to the official Global Fishing Watch API
documentation:

See: https://globalfishingwatch.org/our-apis/documentation#get-all-bulk-reports-by-user

Attributes:
_result_item_class (Type[BulkReportListItem]):
The model used for individual result items.

_data (BulkReportListItem):
The bulk report item returned in the response.
"""

_result_item_class: Type[BulkReportListItem]
_data: List[BulkReportListItem]

def __init__(self, data: List[BulkReportListItem]) -> None:
"""Initializes a new `BulkReportListResult`.

Args:
data (List[BulkReportListItem]):
The list of bulk report items.
"""
super().__init__(data=data)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"limit": 99999,
"offset": 0,
"sort": "-createdAt",
"status": "done"
}
16 changes: 16 additions & 0 deletions tests/resources/bulk_downloads/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,19 @@ def mock_raw_bulk_report_create_request_body(
"bulk_downloads/bulk_report_create_request_body.json"
)
return raw_bulk_report_create_request_body


@pytest.fixture
def mock_raw_bulk_report_list_request_params(
load_json_fixture: Callable[[str], Dict[str, Any]],
) -> Dict[str, Any]:
"""Fixture for mock raw bulk report list request parameters.

Returns:
Dict[str, Any]:
Raw `BulkReportListParams` sample data as dictionary.
"""
raw_bulk_report_list_request_params: Dict[str, Any] = load_json_fixture(
"bulk_downloads/bulk_report_list_request_params.json"
)
return raw_bulk_report_list_request_params
1 change: 1 addition & 0 deletions tests/resources/bulk_downloads/list/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Tests for `gfwapiclient.resources.bulk_downloads.list`."""
1 change: 1 addition & 0 deletions tests/resources/bulk_downloads/list/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Tests for `gfwapiclient.resources.bulk_downloads.create.models`."""
21 changes: 21 additions & 0 deletions tests/resources/bulk_downloads/list/models/test_request_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Tests for `gfwapiclient.resources.bulk_downloads.list.models.request`."""

from typing import Any, Dict

from gfwapiclient.resources.bulk_downloads.list.models.request import (
BulkReportListParams,
)


def test_bulk_report_list_request_params_serializes_all_fields(
mock_raw_bulk_report_list_request_params: Dict[str, Any],
) -> None:
"""Test that `BulkReportListParams` serializes all fields correctly."""
bulk_report_list_request_params: BulkReportListParams = BulkReportListParams(
**mock_raw_bulk_report_list_request_params
)
assert bulk_report_list_request_params.limit is not None
assert bulk_report_list_request_params.offset is not None
assert bulk_report_list_request_params.sort is not None
assert bulk_report_list_request_params.status is not None
assert bulk_report_list_request_params.to_query_params() is not None
38 changes: 38 additions & 0 deletions tests/resources/bulk_downloads/list/models/test_response_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""Tests for `gfwapiclient.resources.bulk_downloads.list.models.response`."""

from typing import Any, Dict, List, cast

from gfwapiclient.resources.bulk_downloads.list.models.response import (
BulkReportListItem,
BulkReportListResult,
)


def test_bulk_report_list_item_deserializes_all_fields(
mock_raw_bulk_report_item: Dict[str, Any],
) -> None:
"""Test that `BulkReportListItem` deserializes all fields correctly."""
bulk_report_list_item: BulkReportListItem = BulkReportListItem(
**mock_raw_bulk_report_item
)
assert bulk_report_list_item.id is not None
assert bulk_report_list_item.name is not None
assert bulk_report_list_item.file_path is not None
assert bulk_report_list_item.format is not None
assert bulk_report_list_item.filters is not None
assert bulk_report_list_item.geom is not None
assert bulk_report_list_item.status is not None
assert bulk_report_list_item.owner_id is not None
assert bulk_report_list_item.owner_type is not None
assert bulk_report_list_item.created_at is not None
assert bulk_report_list_item.updated_at is not None
assert bulk_report_list_item.file_size is not None


def test_bulk_report_list_result_deserializes_all_fields(
mock_raw_bulk_report_item: Dict[str, Any],
) -> None:
"""Test that `BulkReportListResult` deserializes all fields correctly."""
data: List[BulkReportListItem] = [BulkReportListItem(**mock_raw_bulk_report_item)]
result = BulkReportListResult(data=data)
assert cast(List[BulkReportListItem], result.data()) == data
Loading