mirror of
https://github.com/lancedb/lancedb.git
synced 2026-10-31 07:46:51 +00:00
fix(python): implement remote namespace and table existence checks (#4725)
Remote Python connections inherited the unsupported-operation stubs for `namespace_exists` and `table_exists`, so both raised `NotImplementedError` even when namespace and table operations worked. Add the missing remote overrides, async methods, and PyO3 bindings using the existing namespace describe and table open paths. Only an explicit not-found result returns `False`; permission, transport, and server errors propagate. This preserves authentication, dynamic headers, retries, and nested namespace handling, and rechecks cached tables before reporting that they exist. The async namespace helper also recognizes native `NamespaceNotFound` errors so missing local namespaces return `False`. The table and namespace guides document Python remote support and distinguish it from the unsupported `exists` routes used by direct REST namespace clients. Validation: - All 40 focused regression cases pass, covering successful and missing lookups, local and remote namespaces, dynamic headers, permission/server errors, invalid table identifiers, and cached tables that disappear. - The original inherited stubs reproduce the reported `NotImplementedError`; the local namespace regression reproduced the native missing-namespace `RuntimeError` before its fix. - Full remote connection suite: 255 passed. Local namespace tests: 14 passed. - `cargo clippy --quiet -p lancedb-python --features remote --lib`, `cargo fmt --all`, Python Ruff lint, and Python formatting checks pass. - Root `ruff check .` reports 48 existing errors in documentation examples under `docs/web-tests`; the Python subtree passes and those unrelated files are unchanged. Fixes #4722 <!-- lance-gatekeeper-fix:v1 agent=4d369a0681756fdb5a8b35853d7f5607 generation=1 --> --------- Co-authored-by: Gatefixer <313497061+lancedb-gatefixer[bot]@users.noreply.github.com>
This commit is contained in:
@@ -711,6 +711,53 @@ impl Connection {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn namespace_exists(
|
||||
self_: PyRef<'_, Self>,
|
||||
namespace_id: Vec<String>,
|
||||
) -> PyResult<Bound<'_, PyAny>> {
|
||||
let inner = self_.get_inner()?.clone();
|
||||
future_into_py(self_.py(), async move {
|
||||
let request = lance_namespace::models::DescribeNamespaceRequest {
|
||||
id: Some(namespace_id),
|
||||
..Default::default()
|
||||
};
|
||||
match inner.describe_namespace(request).await {
|
||||
Ok(_) => Ok(true),
|
||||
Err(lancedb::Error::Http {
|
||||
status_code: Some(status),
|
||||
..
|
||||
}) if status.as_u16() == 404 => Ok(false),
|
||||
Err(lancedb::Error::Lance {
|
||||
source: lance_core::Error::Namespace { ref source, .. },
|
||||
}) if matches!(
|
||||
source.downcast_ref::<lance_namespace::NamespaceError>(),
|
||||
Some(lance_namespace::NamespaceError::NamespaceNotFound { .. })
|
||||
) =>
|
||||
{
|
||||
Ok(false)
|
||||
}
|
||||
Err(err) => Err(err).infer_error(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn table_exists(
|
||||
self_: PyRef<'_, Self>,
|
||||
mut table_id: Vec<String>,
|
||||
) -> PyResult<Bound<'_, PyAny>> {
|
||||
let inner = self_.get_inner()?.clone();
|
||||
let name = table_id
|
||||
.pop()
|
||||
.ok_or_else(|| PyValueError::new_err("table_id must include a table name"))?;
|
||||
future_into_py(self_.py(), async move {
|
||||
match inner.open_table(name).namespace(table_id).execute().await {
|
||||
Ok(_) => Ok(true),
|
||||
Err(lancedb::Error::TableNotFound { .. }) => Ok(false),
|
||||
Err(err) => Err(err).infer_error(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[pyo3(signature = (namespace_path=None, page_token=None, limit=None))]
|
||||
pub fn list_tables(
|
||||
&self,
|
||||
|
||||
Reference in New Issue
Block a user