Skip to content

Commit

Permalink
An asset module and simple API (#566)
Browse files Browse the repository at this point in the history
* Initial tests

Implementation is in the tests at this stage.

* Move implementation to new module

* Add Ctx, tests against production assets

* Add delete()

Remove config for an uninstalled pytest plugin

* Restore pytest explicit-only config, add dev and tests deps

* Use public group and array

* Move all mocking outside the test functions

* Switch to relative tiledb.cloud imports

* Add a change log
  • Loading branch information
sgillies authored May 28, 2024
1 parent 18c0a7e commit 43ca0f3
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 3 deletions.
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Changes

## Next (YYYY-MM-DD)

- Add a tiledb.cloud.asset module with functions that allow management of
assets of any type (gh-566).
4 changes: 1 addition & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,12 @@ viz-plotly = ["networkx>=2", "plotly>=4", "pydot"]
all = ["networkx>=2", "plotly>=4", "pydot", "tiledb-plot-widget>=0.1.7"]

dev = ["black", "pytest", "ruff"]
tests = ["xarray", "pytest-split"]
tests = ["xarray", "pytest-cov", "pytest-explicit", "pytest-split"]

[project.urls]
homepage = "https://tiledb.com"
repository = "https://github.com/TileDB-Inc/TileDB-Cloud-Py"


[build-system]
requires = ["setuptools>=42", "wheel", "setuptools_scm>=6"]

Expand All @@ -48,7 +47,6 @@ markers = [
]
norecursedirs = ["tiledb/cloud"]


[tool.setuptools]
zip-safe = false

Expand Down
40 changes: 40 additions & 0 deletions src/tiledb/cloud/asset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""An asset may be an array or a group."""

from functools import partial
from typing import Union

import tiledb # type: ignore

from . import array # type: ignore
from . import groups # type: ignore
from .rest_api.models import ArrayInfo # type: ignore
from .rest_api.models import GroupInfo # type: ignore


def delete(uri: str, recursive: bool = False) -> None:
"""Deregister the asset and remove its physical groups and arrays from storage.
:param uri: URI of the asset.
:return: None.
"""
delete_map = {
"array": array.delete_array,
"group": partial(groups.delete, recursive=recursive),
}
asset_type = tiledb.object_type(uri, ctx=tiledb.cloud.Ctx())
func = delete_map[asset_type]
return func(uri)


def info(uri: str) -> Union[ArrayInfo, GroupInfo]:
"""Retrieve information about an asset.
:param uri: URI of the asset.
:return: ArrayInfo or GroupInfo.
"""
# Note: the URI can be either of the two forms, yes?
# tiledb://namespace/name or tiledb://namespace/UUID.
info_map = {"array": array.info, "group": groups.info}
asset_type = tiledb.object_type(uri, ctx=tiledb.cloud.Ctx())
func = info_map[asset_type]
return func(uri)
66 changes: 66 additions & 0 deletions tests/test_asset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""Tests of the tiledb.cloud.asset module."""

from unittest import mock

from tiledb.cloud.asset import delete # type: ignore
from tiledb.cloud.asset import info # type: ignore
from tiledb.cloud.rest_api.models import ArrayInfo # type: ignore
from tiledb.cloud.rest_api.models import GroupInfo # type: ignore


@mock.patch("tiledb.object_type", return_value="array")
@mock.patch("tiledb.cloud.array.delete_array")
def test_asset_delete_array_dispatch(delete_array, object_type):
"""Dispatch to array.array_delete when URI is an array."""
delete("a")
# Since delete() doesn't return a value, we assert on the implementation.
delete_array.assert_called_once_with("a")


@mock.patch("tiledb.object_type", return_value="group")
@mock.patch("tiledb.cloud.groups.delete")
def test_asset_delete_group_dispatch(delete_group, object_type):
"""Dispatch to groups.delete when URI is a group."""
delete("g")
# Since delete() doesn't return a value, we assert on the implementation.
delete_group.assert_called_once_with("g", recursive=False)


@mock.patch("tiledb.object_type", return_value="group")
@mock.patch("tiledb.cloud.groups.delete")
def test_asset_delete_group_recursive(delete_group, object_type):
"""Dispatch to groups.delete, recursively, when URI is a group."""
delete("g", recursive=True)
# Since delete() doesn't return a value, we assert on the implementation.
delete_group.assert_called_once_with("g", recursive=True)


@mock.patch("tiledb.object_type", return_value="array")
@mock.patch("tiledb.cloud.array.info", return_value=ArrayInfo(tiledb_uri="tiledb://a"))
def test_asset_info_array_dispatch(array_info, object_type):
"""Dispatch to array.info when URI is an array."""
asset_info = info("a")
assert isinstance(asset_info, ArrayInfo)
assert asset_info.tiledb_uri == "tiledb://a"


@mock.patch("tiledb.object_type", return_value="group")
@mock.patch("tiledb.cloud.groups.info", return_value=GroupInfo(tiledb_uri="tiledb://g"))
def test_asset_info_group_dispatch(group_info, object_type):
"""Dispatch to groups.info when URI is a group."""
asset_info = info("g")
assert isinstance(asset_info, GroupInfo)
assert asset_info.tiledb_uri == "tiledb://g"


def test_public_array_asset_info():
"""Get info about a public production array."""
asset_info = info("tiledb://TileDB-Inc/cd89a0d6-c262-4729-9e75-d942879e1d7d")
assert asset_info.name == "documents"
assert asset_info.type == "sparse"


def test_public_group_asset_info():
"""Get info about a public production group."""
asset_info = info("tiledb://TileDB-Inc/52165567-040c-4e75-bb89-a3d06017f650")
assert asset_info.name == "langchain_documentation_huggingface"

0 comments on commit 43ca0f3

Please sign in to comment.