From d52940cdabcc4536f68d7cb7add13ee3bc4bf26b Mon Sep 17 00:00:00 2001 From: Gatefixer <313497061+lancedb-gatefixer[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 13:33:39 +0000 Subject: [PATCH] fix: guard UNC namespace client exports --- python/python/lancedb/namespace.py | 24 ++------------- python/python/tests/test_db.py | 34 +++++++++++++++++++++ python/python/tests/test_namespace.py | 41 ++++++++++++++++++++++++++ rust/lancedb/src/database/namespace.rs | 5 ++++ 4 files changed, 82 insertions(+), 22 deletions(-) diff --git a/python/python/lancedb/namespace.py b/python/python/lancedb/namespace.py index b151395cc..141e50aab 100644 --- a/python/python/lancedb/namespace.py +++ b/python/python/lancedb/namespace.py @@ -919,17 +919,7 @@ class LanceNamespaceDBConnection(DBConnection): The namespace client for this connection. """ if self._namespace_client is None: - if ( - self._namespace_client_impl is None - or self._namespace_client_properties is None - ): - raise ValueError( - "Cannot construct a Python namespace client without " - "namespace implementation properties" - ) - self._namespace_client = namespace_connect( - self._namespace_client_impl, self._namespace_client_properties - ) + self._namespace_client = LOOP.run(self._inner.namespace_client()) return self._namespace_client @@ -1370,17 +1360,7 @@ class AsyncLanceNamespaceDBConnection: The namespace client for this connection. """ if self._namespace_client is None: - if ( - self._namespace_client_impl is None - or self._namespace_client_properties is None - ): - raise ValueError( - "Cannot construct a Python namespace client without " - "namespace implementation properties" - ) - self._namespace_client = namespace_connect( - self._namespace_client_impl, self._namespace_client_properties - ) + self._namespace_client = await self._inner.namespace_client() return self._namespace_client diff --git a/python/python/tests/test_db.py b/python/python/tests/test_db.py index 423aa85d3..48548f0a5 100644 --- a/python/python/tests/test_db.py +++ b/python/python/tests/test_db.py @@ -1230,6 +1230,40 @@ def test_clone_table_deep_clone_fails(tmp_path): db.clone_table("cloned", source_uri, is_shallow=False) +class _UnsupportedNamespaceConfig: + async def namespace_client_config(self): + raise RuntimeError("UNC namespace client export is not supported") + + +def test_sync_namespace_client_propagates_export_guard(monkeypatch): + from lancedb.db import AsyncConnection, LanceDBConnection + + monkeypatch.setattr( + "lancedb.db.namespace_connect", + lambda *_args, **_kwargs: pytest.fail("guarded config was reconstructed"), + ) + db = LanceDBConnection.__new__(LanceDBConnection) + db._conn = AsyncConnection(_UnsupportedNamespaceConfig()) + db._cached_namespace_client = None + + with pytest.raises(RuntimeError, match="UNC namespace client export"): + db.namespace_client() + + +@pytest.mark.asyncio +async def test_async_namespace_client_propagates_export_guard(monkeypatch): + from lancedb.db import AsyncConnection + + monkeypatch.setattr( + "lancedb.db.namespace_connect", + lambda *_args, **_kwargs: pytest.fail("guarded config was reconstructed"), + ) + db = AsyncConnection(_UnsupportedNamespaceConfig()) + + with pytest.raises(RuntimeError, match="UNC namespace client export"): + await db.namespace_client() + + @pytest.mark.skipif(sys.platform == "win32", reason="Namespace client issues") def test_namespace_client_native_storage(tmp_path): """Test namespace_client() returns DirectoryNamespace for native storage.""" diff --git a/python/python/tests/test_namespace.py b/python/python/tests/test_namespace.py index f8cbfe92c..6ee576627 100644 --- a/python/python/tests/test_namespace.py +++ b/python/python/tests/test_namespace.py @@ -60,6 +60,11 @@ class _NamespaceClient: return _ipc_file() +class _UnsupportedNamespaceConfig: + async def namespace_client_config(self): + raise RuntimeError("UNC namespace client export is not supported") + + def _namespace_lance_table(namespace_client: _NamespaceClient) -> LanceTable: table = LanceTable.__new__(LanceTable) table._table = _FailingSyncInner() @@ -138,6 +143,24 @@ class TestNamespaceConnection: db.drop_namespace(["test_ns"]) assert "test_ns" not in db.list_namespaces().namespaces + def test_sync_namespace_client_propagates_export_guard(self, monkeypatch): + from lancedb.db import AsyncConnection + + monkeypatch.setattr( + "lancedb.namespace.namespace_connect", + lambda *_args, **_kwargs: pytest.fail("guarded config was reconstructed"), + ) + db = lancedb.LanceNamespaceDBConnection.__new__( + lancedb.LanceNamespaceDBConnection + ) + db._namespace_client = None + db._namespace_client_impl = "dir" + db._namespace_client_properties = {"root": "file://server/share/database"} + db._inner = AsyncConnection(_UnsupportedNamespaceConfig()) + + with pytest.raises(RuntimeError, match="UNC namespace client export"): + db.namespace_client() + def test_create_table_through_namespace(self): """Test creating a table through namespace.""" db = lancedb.connect_namespace("dir", {"root": self.temp_dir}) @@ -639,6 +662,24 @@ class TestAsyncNamespaceConnection: await db.drop_namespace(["test_ns"]) assert "test_ns" not in (await db.list_namespaces()).namespaces + async def test_async_namespace_client_propagates_export_guard(self, monkeypatch): + from lancedb.db import AsyncConnection + + monkeypatch.setattr( + "lancedb.namespace.namespace_connect", + lambda *_args, **_kwargs: pytest.fail("guarded config was reconstructed"), + ) + db = lancedb.AsyncLanceNamespaceDBConnection.__new__( + lancedb.AsyncLanceNamespaceDBConnection + ) + db._namespace_client = None + db._namespace_client_impl = "dir" + db._namespace_client_properties = {"root": "file://server/share/database"} + db._inner = AsyncConnection(_UnsupportedNamespaceConfig()) + + with pytest.raises(RuntimeError, match="UNC namespace client export"): + await db.namespace_client() + async def test_async_namespace_client_is_lazy(self): """namespace_client() should still return the backing client on demand.""" pytest.importorskip("lance") diff --git a/rust/lancedb/src/database/namespace.rs b/rust/lancedb/src/database/namespace.rs index f64229474..4efab9f38 100644 --- a/rust/lancedb/src/database/namespace.rs +++ b/rust/lancedb/src/database/namespace.rs @@ -697,6 +697,7 @@ impl Database for LanceNamespaceDatabase { } async fn namespace_client_config(&self) -> Result<(String, HashMap)> { + self.ensure_storage_supported()?; Ok((self.ns_impl.clone(), self.ns_properties.clone())) } } @@ -769,6 +770,10 @@ mod tests { .unwrap_err(); assert!(matches!(error, Error::NotSupported { .. })); assert!(error.to_string().contains("UNC roots")); + + let error = db.namespace_client_config().await.unwrap_err(); + assert!(matches!(error, Error::NotSupported { .. })); + assert!(error.to_string().contains("UNC roots")); } #[tokio::test]