Skip to content

Commit 1393bde

Browse files
committed
feat(gooddata-sdk): [AUTO] Rename /ailake/object-storages path to /ailake/objectStorages
1 parent 38b0798 commit 1393bde

7 files changed

Lines changed: 94 additions & 6 deletions

File tree

packages/gooddata-sdk/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ test = [
7676
]
7777

7878
[tool.ty.analysis]
79-
allowed-unresolved-imports = ["gooddata_api_client.**"]
79+
allowed-unresolved-imports = ["gooddata_api_client.**", "pyarrow"]
8080

8181
[tool.hatch.build.targets.wheel]
8282
packages = ["src/gooddata_sdk"]

packages/gooddata-sdk/src/gooddata_sdk/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
CatalogAILakeOperation,
1212
CatalogAILakeOperationError,
1313
CatalogAILakeService,
14+
CatalogObjectStorageInfo,
1415
)
1516
from gooddata_sdk.catalog.appearance.entity_model.color_palette import (
1617
CatalogColorPalette,

packages/gooddata-sdk/src/gooddata_sdk/catalog/ai_lake/service.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
from gooddata_sdk.catalog.base import Base
3030
from gooddata_sdk.client import GoodDataApiClient
3131

32+
_OBJECT_STORAGES_PATH = "api/v1/ailake/objectStorages"
33+
3234
# AI Lake operation status values (lower-case on the wire — these are the
3335
# discriminator values of the `Operation` oneOf on the OpenAPI side).
3436
OperationStatus = Literal["pending", "succeeded", "failed"]
@@ -58,6 +60,25 @@ def is_failed(self) -> bool:
5860
return self.status == "failed"
5961

6062

63+
@define(kw_only=True)
64+
class CatalogObjectStorageInfo(Base):
65+
"""Information about a registered AI Lake object storage."""
66+
67+
name: str
68+
storage_config: dict[str, str]
69+
storage_id: str
70+
storage_type: str
71+
72+
@classmethod
73+
def from_api(cls, entity: dict[str, Any]) -> CatalogObjectStorageInfo:
74+
return cls(
75+
name=entity["name"],
76+
storage_config=entity.get("storageConfig") or {},
77+
storage_id=entity["storageId"],
78+
storage_type=entity["storageType"],
79+
)
80+
81+
6182
class CatalogAILakeOperationError(RuntimeError):
6283
"""Raised when an AI Lake long-running operation finishes in `failed` state."""
6384

@@ -76,6 +97,22 @@ def __init__(self, api_client: GoodDataApiClient) -> None:
7697
self._client = api_client
7798
self._ai_lake_api: AILakeApi = AILakeApi(api_client._api_client)
7899

100+
def list_object_storages(self) -> list[CatalogObjectStorageInfo]:
101+
"""List all object storages registered for the organization.
102+
103+
Uses the new `/api/v1/ailake/objectStorages` path (renamed from
104+
the legacy `/api/v1/ailake/object-storages`). The generated
105+
api-client still references the old path, so this method bypasses
106+
it and calls the endpoint directly.
107+
108+
Returns:
109+
List of `CatalogObjectStorageInfo` objects, ordered by name.
110+
"""
111+
response = self._client._do_get_request(_OBJECT_STORAGES_PATH)
112+
response.raise_for_status()
113+
data: dict[str, Any] = response.json()
114+
return [CatalogObjectStorageInfo.from_api(s) for s in data.get("storages", [])]
115+
79116
def analyze_statistics(
80117
self,
81118
instance_id: str,

packages/gooddata-sdk/src/gooddata_sdk/client.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,30 @@ def __init__(
9191
self._ai_lake_api = apis.AILakeApi(self._api_client)
9292
self._executions_cancellable = executions_cancellable
9393

94+
def _do_get_request(
95+
self,
96+
endpoint: str,
97+
) -> requests.Response:
98+
"""Perform a GET request to a specified endpoint.
99+
100+
Args:
101+
endpoint (str): The endpoint URL to which the request is made.
102+
103+
Returns:
104+
requests.Response: The response from the HTTP request.
105+
"""
106+
if not self._hostname.endswith("/"):
107+
endpoint = f"/{endpoint}"
108+
109+
response = requests.get(
110+
url=f"{self._hostname}{endpoint}",
111+
headers={
112+
"Authorization": f"Bearer {self._token}",
113+
},
114+
)
115+
116+
return response
117+
94118
def _do_post_request(
95119
self,
96120
data: bytes,

packages/gooddata-sdk/src/gooddata_sdk/compute/model/execution.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
import pyarrow as _pyarrow
2020
from pyarrow import ipc as _ipc
2121
except ImportError:
22-
_pyarrow = None # type: ignore
23-
_ipc = None # type: ignore
22+
_pyarrow = None
23+
_ipc = None
2424

2525
from gooddata_sdk.client import GoodDataApiClient
2626
from gooddata_sdk.compute.model.attribute import Attribute

packages/gooddata-sdk/src/gooddata_sdk/compute/model/filter.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ def __init__(
326326
self._from_shift = from_shift
327327
self._to_shift = to_shift
328328
self._bounded_filter = bounded_filter
329-
self._empty_value_handling = empty_value_handling
329+
self._empty_value_handling: EmptyValueHandling | None = empty_value_handling
330330

331331
@property
332332
def dataset(self) -> ObjId:
@@ -435,7 +435,7 @@ def __init__(
435435

436436
self._dataset = dataset
437437
self._granularity = granularity
438-
self._empty_value_handling = empty_value_handling
438+
self._empty_value_handling: EmptyValueHandling | None = empty_value_handling
439439

440440
@property
441441
def dataset(self) -> ObjId:
@@ -490,7 +490,7 @@ def __init__(
490490
self._dataset = dataset
491491
self._from_date = from_date
492492
self._to_date = to_date
493-
self._empty_value_handling = empty_value_handling
493+
self._empty_value_handling: EmptyValueHandling | None = empty_value_handling
494494

495495
@property
496496
def dataset(self) -> ObjId:
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# (C) 2026 GoodData Corporation
2+
"""Integration tests for `CatalogAILakeService`."""
3+
4+
from __future__ import annotations
5+
6+
from pathlib import Path
7+
8+
from gooddata_sdk import CatalogObjectStorageInfo, GoodDataSdk
9+
from tests_support.vcrpy_utils import get_vcr
10+
11+
gd_vcr = get_vcr()
12+
13+
_current_dir = Path(__file__).parent.absolute()
14+
_fixtures_dir = _current_dir / "fixtures" / "ai_lake"
15+
16+
17+
@gd_vcr.use_cassette(str(_fixtures_dir / "test_list_object_storages.yaml"))
18+
def test_list_object_storages(test_config):
19+
sdk = GoodDataSdk.create(host_=test_config["host"], token_=test_config["token"])
20+
storages = sdk.catalog_ai_lake.list_object_storages()
21+
assert isinstance(storages, list)
22+
for s in storages:
23+
assert isinstance(s, CatalogObjectStorageInfo)
24+
assert s.name
25+
assert s.storage_id
26+
assert s.storage_type

0 commit comments

Comments
 (0)