Skip to content
Draft
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
40 changes: 36 additions & 4 deletions audmodel/core/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1068,6 +1068,41 @@ def update_meta(
return meta_backend


def _url(
backend_interface: audbackend.interface.Base,
path: str,
) -> str:
r"""Convert a backend path into a URL.

Depending on the underlying backend
of the given backend interface,
the path on the backend
is turned into a URL
Comment on lines +1071 to +1080

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Behavior for unsupported backend types may not match the function’s URL-centric contract.

The docstring says _url converts a backend path into a URL, but for backends other than FileSystem and Minio it returns the raw path. This can mask misconfigurations or new backend types that aren’t wired up correctly. Consider failing explicitly (e.g., raising for unsupported backends), returning None, or updating the docs to state that non-URL-capable backends return the backend-relative path unchanged.

pointing to the corresponding file.

Args:
backend_interface: backend interface
path: path on the backend, including version

Returns:
URL to the file on the backend

"""
backend = backend_interface.backend
if isinstance(backend, audbackend.backend.FileSystem):
path = backend_interface.sep.join([backend._root, path])
elif isinstance(backend, audbackend.backend.Minio):
scheme = "https" if backend._client._base_url.is_https else "http"
path = backend_interface.sep.join(
[
f"{scheme}://{backend.host}",
backend.repository,
backend.path(path),
]
)
return path


def url(
uid: str,
*,
Expand Down Expand Up @@ -1133,10 +1168,7 @@ def url(
f"'type' has to be one of 'model', 'header', 'meta', not '{type}'"
)
path = backend_interface._path_with_version(path, version)
# Check for underlying backend of backend interface
if isinstance(backend_interface.backend, audbackend.backend.FileSystem):
path = backend_interface.sep.join([backend_interface.backend._root, path])
return path
return _url(backend_interface, path)


def version(
Expand Down
52 changes: 46 additions & 6 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import audeer

import audmodel
import audmodel.core.api
import audmodel.core.define as define


audmodel.config.CACHE_ROOT = pytest.CACHE_ROOT
Expand Down Expand Up @@ -284,11 +286,49 @@ def test_update_meta():


def test_url():
uid = audmodel.uid(
pytest.NAME,
pytest.PARAMS,
"1.0.0",
subgroup=SUBGROUP,
)

# Wrong type
with pytest.raises(ValueError):
uid = audmodel.uid(
pytest.NAME,
pytest.PARAMS,
"1.0.0",
subgroup=SUBGROUP,
)
audmodel.url(uid, type="something")

# File-system backend
# (the test models are published to a file-system repository)
for type, ext in [
("model", "zip"),
("header", "header.yaml"),
("meta", "meta.yaml"),
]:
path = audmodel.url(uid, type=type)
assert os.path.exists(path)
assert path.startswith(audeer.path(pytest.HOST, pytest.REPOSITORIES[0].name))
assert os.path.basename(path) == f"{uid}.{ext}"


def test_url_minio():
"""URL construction for the Minio/S3 backend.

The Minio backend is not tested against a running server,
so we verify the URL construction
of the helper function directly.

"""
host = "s3.dualstack.eu-north-1.amazonaws.com"
repository = "audmodel-public"
repository_object = audmodel.Repository(repository, host, "s3")
backend_interface = repository_object.create_backend_interface()

path = backend_interface.join(
"/", define.UID_FOLDER, f"d4e9c65b.{define.HEADER_EXT}"
)
path = backend_interface._path_with_version(path, "3.0.0")

url = audmodel.core.api._url(backend_interface, path)
assert url == (
f"https://{host}/{repository}/_uid/d4e9c65b/3.0.0/d4e9c65b-3.0.0.header.yaml"
)
Loading