From 207028cdf78b29e7ddcce2f5a78999bd9a0daf93 Mon Sep 17 00:00:00 2001 From: TheeCoderAhmed Date: Thu, 29 Oct 2026 06:45:43 +0300 Subject: [PATCH] fix: include the store location in ObjectRef.full_path For s3, gcs and azure stores, full_path built :/// and left out the store's location, so it pointed to a path where the object is not when location is set. Use StorageBackend.get_url(), which builds the URL from the same _full_path the backend writes to. Fixes #1646 --- src/datajoint/objectref.py | 11 ++--------- tests/unit/test_objectref.py | 38 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 9 deletions(-) create mode 100644 tests/unit/test_objectref.py diff --git a/src/datajoint/objectref.py b/src/datajoint/objectref.py index c312e0c5d..9bd09f0bf 100644 --- a/src/datajoint/objectref.py +++ b/src/datajoint/objectref.py @@ -174,15 +174,8 @@ def full_path(self) -> str: protocol = self._backend.protocol if protocol == "file": return str(Path(self._backend.spec.get("location", "")) / self.path) - elif protocol == "s3": - bucket = self._backend.spec["bucket"] - return f"s3://{bucket}/{self.path}" - elif protocol == "gcs": - bucket = self._backend.spec["bucket"] - return f"gs://{bucket}/{self.path}" - elif protocol == "azure": - container = self._backend.spec["container"] - return f"az://{container}/{self.path}" + elif protocol in ("s3", "gcs", "azure"): + return self._backend.get_url(self.path) else: return self.path diff --git a/tests/unit/test_objectref.py b/tests/unit/test_objectref.py new file mode 100644 index 000000000..f0e70220a --- /dev/null +++ b/tests/unit/test_objectref.py @@ -0,0 +1,38 @@ +"""Unit tests for ObjectRef.""" + +from datetime import datetime, timezone + +import pytest + +from datajoint.objectref import ObjectRef +from datajoint.storage import StorageBackend + + +def _object_ref(spec): + return ObjectRef( + path="_schema/scratch/result/data_abc.txt", + size=5, + hash=None, + ext=".txt", + is_dir=False, + timestamp=datetime.now(timezone.utc), + _backend=StorageBackend(spec), + ) + + +@pytest.mark.parametrize( + ("spec", "prefix"), + [ + ( + {"protocol": "s3", "endpoint": "localhost:9000", "bucket": "bkt", "location": "proj/outbox"}, + "s3://bkt/proj/outbox/", + ), + ({"protocol": "s3", "endpoint": "localhost:9000", "bucket": "bkt"}, "s3://bkt/"), + ({"protocol": "gcs", "bucket": "bkt", "location": "proj"}, "gs://bkt/proj/"), + ({"protocol": "azure", "container": "ctr", "location": "proj"}, "az://ctr/proj/"), + ], +) +def test_full_path_includes_store_location(spec, prefix): + """full_path points where the backend stores the object, location included.""" + ref = _object_ref(spec) + assert ref.full_path == prefix + ref.path