Compare commits

..

1 Commits

Author SHA1 Message Date
LanceDB Robot
4da01a0e65 chore: update lance dependency to v2.0.0-beta.8 (#2907)
## Summary
- bump Lance crates to v2.0.0-beta.8 and align
arrow/datafusion/regex/half and PyO3 dependencies
- update Rust/Python bindings for upstream API changes (namespace/table
requests, query select columns, storage option providers)
- verified with cargo clippy --workspace --tests --all-features -D
warnings and cargo fmt --all

Triggered by refs/tags/v2.0.0-beta.8.

---------

Signed-off-by: BubbleCal <bubble-cal@outlook.com>
Co-authored-by: BubbleCal <bubble-cal@outlook.com>
2026-01-16 01:46:52 +08:00
16 changed files with 252 additions and 222 deletions

68
Cargo.lock generated
View File

@@ -3072,8 +3072,8 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
[[package]]
name = "fsst"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"arrow-array",
"rand 0.9.2",
@@ -4404,8 +4404,8 @@ dependencies = [
[[package]]
name = "lance"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"arrow",
"arrow-arith",
@@ -4470,8 +4470,8 @@ dependencies = [
[[package]]
name = "lance-arrow"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"arrow-array",
"arrow-buffer",
@@ -4490,8 +4490,8 @@ dependencies = [
[[package]]
name = "lance-bitpacking"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"arrayref",
"paste",
@@ -4500,8 +4500,8 @@ dependencies = [
[[package]]
name = "lance-core"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"arrow-array",
"arrow-buffer",
@@ -4538,8 +4538,8 @@ dependencies = [
[[package]]
name = "lance-datafusion"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"arrow",
"arrow-array",
@@ -4569,8 +4569,8 @@ dependencies = [
[[package]]
name = "lance-datagen"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"arrow",
"arrow-array",
@@ -4588,8 +4588,8 @@ dependencies = [
[[package]]
name = "lance-encoding"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"arrow-arith",
"arrow-array",
@@ -4626,8 +4626,8 @@ dependencies = [
[[package]]
name = "lance-file"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"arrow-arith",
"arrow-array",
@@ -4659,8 +4659,8 @@ dependencies = [
[[package]]
name = "lance-geo"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"datafusion",
"geo-traits",
@@ -4674,8 +4674,8 @@ dependencies = [
[[package]]
name = "lance-index"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"arrow",
"arrow-arith",
@@ -4742,8 +4742,8 @@ dependencies = [
[[package]]
name = "lance-io"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"arrow",
"arrow-arith",
@@ -4783,8 +4783,8 @@ dependencies = [
[[package]]
name = "lance-linalg"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"arrow-array",
"arrow-buffer",
@@ -4800,8 +4800,8 @@ dependencies = [
[[package]]
name = "lance-namespace"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"arrow",
"async-trait",
@@ -4813,8 +4813,8 @@ dependencies = [
[[package]]
name = "lance-namespace-impls"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"arrow",
"arrow-ipc",
@@ -4857,8 +4857,8 @@ dependencies = [
[[package]]
name = "lance-table"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"arrow",
"arrow-array",
@@ -4897,8 +4897,8 @@ dependencies = [
[[package]]
name = "lance-testing"
version = "2.0.0-beta.9"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.9#768bf30973ad28c892bfbae98d87bdf9a2139139"
version = "2.0.0-beta.8"
source = "git+https://github.com/lance-format/lance.git?tag=v2.0.0-beta.8#5bffcfc3f9716fd6eb069579eb5027ed9c69feb7"
dependencies = [
"arrow-array",
"arrow-schema",

View File

@@ -15,20 +15,20 @@ categories = ["database-implementations"]
rust-version = "1.78.0"
[workspace.dependencies]
lance = { "version" = "=2.0.0-beta.9", default-features = false, "tag" = "v2.0.0-beta.9", "git" = "https://github.com/lance-format/lance.git" }
lance-core = { "version" = "=2.0.0-beta.9", "tag" = "v2.0.0-beta.9", "git" = "https://github.com/lance-format/lance.git" }
lance-datagen = { "version" = "=2.0.0-beta.9", "tag" = "v2.0.0-beta.9", "git" = "https://github.com/lance-format/lance.git" }
lance-file = { "version" = "=2.0.0-beta.9", "tag" = "v2.0.0-beta.9", "git" = "https://github.com/lance-format/lance.git" }
lance-io = { "version" = "=2.0.0-beta.9", default-features = false, "tag" = "v2.0.0-beta.9", "git" = "https://github.com/lance-format/lance.git" }
lance-index = { "version" = "=2.0.0-beta.9", "tag" = "v2.0.0-beta.9", "git" = "https://github.com/lance-format/lance.git" }
lance-linalg = { "version" = "=2.0.0-beta.9", "tag" = "v2.0.0-beta.9", "git" = "https://github.com/lance-format/lance.git" }
lance-namespace = { "version" = "=2.0.0-beta.9", "tag" = "v2.0.0-beta.9", "git" = "https://github.com/lance-format/lance.git" }
lance-namespace-impls = { "version" = "=2.0.0-beta.9", default-features = false, "tag" = "v2.0.0-beta.9", "git" = "https://github.com/lance-format/lance.git" }
lance-table = { "version" = "=2.0.0-beta.9", "tag" = "v2.0.0-beta.9", "git" = "https://github.com/lance-format/lance.git" }
lance-testing = { "version" = "=2.0.0-beta.9", "tag" = "v2.0.0-beta.9", "git" = "https://github.com/lance-format/lance.git" }
lance-datafusion = { "version" = "=2.0.0-beta.9", "tag" = "v2.0.0-beta.9", "git" = "https://github.com/lance-format/lance.git" }
lance-encoding = { "version" = "=2.0.0-beta.9", "tag" = "v2.0.0-beta.9", "git" = "https://github.com/lance-format/lance.git" }
lance-arrow = { "version" = "=2.0.0-beta.9", "tag" = "v2.0.0-beta.9", "git" = "https://github.com/lance-format/lance.git" }
lance = { "version" = "=2.0.0-beta.8", default-features = false, "tag" = "v2.0.0-beta.8", "git" = "https://github.com/lance-format/lance.git" }
lance-core = { "version" = "=2.0.0-beta.8", "tag" = "v2.0.0-beta.8", "git" = "https://github.com/lance-format/lance.git" }
lance-datagen = { "version" = "=2.0.0-beta.8", "tag" = "v2.0.0-beta.8", "git" = "https://github.com/lance-format/lance.git" }
lance-file = { "version" = "=2.0.0-beta.8", "tag" = "v2.0.0-beta.8", "git" = "https://github.com/lance-format/lance.git" }
lance-io = { "version" = "=2.0.0-beta.8", default-features = false, "tag" = "v2.0.0-beta.8", "git" = "https://github.com/lance-format/lance.git" }
lance-index = { "version" = "=2.0.0-beta.8", "tag" = "v2.0.0-beta.8", "git" = "https://github.com/lance-format/lance.git" }
lance-linalg = { "version" = "=2.0.0-beta.8", "tag" = "v2.0.0-beta.8", "git" = "https://github.com/lance-format/lance.git" }
lance-namespace = { "version" = "=2.0.0-beta.8", "tag" = "v2.0.0-beta.8", "git" = "https://github.com/lance-format/lance.git" }
lance-namespace-impls = { "version" = "=2.0.0-beta.8", default-features = false, "tag" = "v2.0.0-beta.8", "git" = "https://github.com/lance-format/lance.git" }
lance-table = { "version" = "=2.0.0-beta.8", "tag" = "v2.0.0-beta.8", "git" = "https://github.com/lance-format/lance.git" }
lance-testing = { "version" = "=2.0.0-beta.8", "tag" = "v2.0.0-beta.8", "git" = "https://github.com/lance-format/lance.git" }
lance-datafusion = { "version" = "=2.0.0-beta.8", "tag" = "v2.0.0-beta.8", "git" = "https://github.com/lance-format/lance.git" }
lance-encoding = { "version" = "=2.0.0-beta.8", "tag" = "v2.0.0-beta.8", "git" = "https://github.com/lance-format/lance.git" }
lance-arrow = { "version" = "=2.0.0-beta.8", "tag" = "v2.0.0-beta.8", "git" = "https://github.com/lance-format/lance.git" }
ahash = "0.8"
# Note that this one does not include pyarrow
arrow = { version = "57.2", optional = false }
@@ -47,7 +47,7 @@ datafusion-execution = "51.0"
datafusion-expr = "51.0"
datafusion-physical-plan = "51.0"
env_logger = "0.11"
half = { "version" = "2.6.0", default-features = false, features = [
half = { "version" = "2.7.1", default-features = false, features = [
"num-traits",
] }
futures = "0"
@@ -59,7 +59,7 @@ rand = "0.9"
snafu = "0.8"
url = "2"
num-traits = "0.2"
regex = "1.10"
regex = "1.12"
lazy_static = "1"
semver = "1.0.25"
chrono = "0.4"

View File

@@ -961,22 +961,27 @@ class LanceQueryBuilder(ABC):
>>> query = [100, 100]
>>> plan = table.search(query).analyze_plan()
>>> print(plan) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
AnalyzeExec verbose=true, metrics=[], cumulative_cpu=...
TracedExec, metrics=[], cumulative_cpu=...
ProjectionExec: expr=[...], metrics=[...], cumulative_cpu=...
GlobalLimitExec: skip=0, fetch=10, metrics=[...], cumulative_cpu=...
FilterExec: _distance@2 IS NOT NULL,
metrics=[output_rows=..., elapsed_compute=...], cumulative_cpu=...
SortExec: TopK(fetch=10), expr=[...],
AnalyzeExec verbose=true, elapsed=..., metrics=...
TracedExec, elapsed=..., metrics=...
ProjectionExec: elapsed=..., expr=[...],
metrics=[output_rows=..., elapsed_compute=..., output_bytes=...]
GlobalLimitExec: elapsed=..., skip=0, fetch=10,
metrics=[output_rows=..., elapsed_compute=..., output_bytes=...]
FilterExec: elapsed=..., _distance@2 IS NOT NULL, metrics=[...]
SortExec: elapsed=..., TopK(fetch=10), expr=[...],
preserve_partitioning=[...],
metrics=[output_rows=..., elapsed_compute=..., row_replacements=...],
cumulative_cpu=...
KNNVectorDistance: metric=l2,
metrics=[output_rows=..., elapsed_compute=..., output_batches=...],
cumulative_cpu=...
LanceRead: uri=..., projection=[vector], ...
metrics=[output_rows=..., elapsed_compute=...,
bytes_read=..., iops=..., requests=...], cumulative_cpu=...
metrics=[output_rows=..., elapsed_compute=...,
output_bytes=..., row_replacements=...]
KNNVectorDistance: elapsed=..., metric=l2,
metrics=[output_rows=..., elapsed_compute=...,
output_bytes=..., output_batches=...]
LanceRead: elapsed=..., uri=..., projection=[vector],
num_fragments=..., range_before=None, range_after=None,
row_id=true, row_addr=false,
full_filter=--, refine_filter=--,
metrics=[output_rows=..., elapsed_compute=..., output_bytes=...,
fragments_scanned=..., ranges_scanned=1, rows_scanned=1,
bytes_read=..., iops=..., requests=..., task_wait_time=...]
Returns
-------

View File

@@ -55,12 +55,12 @@ impl RecordBatchStream {
.next()
.await
.ok_or_else(|| PyStopAsyncIteration::new_err(""))?;
Python::attach(|py| {
inner_next
.infer_error()?
.to_pyarrow(py)
.map(|obj| obj.unbind())
})
#[allow(deprecated)]
let py_obj: Py<PyAny> = Python::with_gil(|py| -> PyResult<Py<PyAny>> {
let bound = inner_next.infer_error()?.to_pyarrow(py)?;
Ok(bound.unbind())
})?;
Ok(py_obj)
})
}
}

View File

@@ -297,8 +297,6 @@ impl Connection {
future_into_py(py, async move {
use lance_namespace::models::ListNamespacesRequest;
let request = ListNamespacesRequest {
identity: None,
context: None,
id: if namespace.is_empty() {
None
} else {
@@ -306,9 +304,11 @@ impl Connection {
},
page_token,
limit: limit.map(|l| l as i32),
..Default::default()
};
let response = inner.list_namespaces(request).await.infer_error()?;
Python::attach(|py| -> PyResult<Py<PyDict>> {
#[allow(deprecated)]
Python::with_gil(|py| -> PyResult<Py<PyDict>> {
let dict = PyDict::new(py);
dict.set_item("namespaces", response.namespaces)?;
dict.set_item("page_token", response.page_token)?;
@@ -328,25 +328,25 @@ impl Connection {
let py = self_.py();
future_into_py(py, async move {
use lance_namespace::models::CreateNamespaceRequest;
let mode_value = mode.and_then(|m| match m.to_lowercase().as_str() {
let mode_enum = mode.and_then(|m| match m.to_lowercase().as_str() {
"create" => Some("Create".to_string()),
"exist_ok" => Some("ExistOk".to_string()),
"overwrite" => Some("Overwrite".to_string()),
_ => None,
});
let request = CreateNamespaceRequest {
identity: None,
context: None,
id: if namespace.is_empty() {
None
} else {
Some(namespace)
},
mode: mode_value,
mode: mode_enum,
properties,
..Default::default()
};
let response = inner.create_namespace(request).await.infer_error()?;
Python::attach(|py| -> PyResult<Py<PyDict>> {
#[allow(deprecated)]
Python::with_gil(|py| -> PyResult<Py<PyDict>> {
let dict = PyDict::new(py);
dict.set_item("properties", response.properties)?;
Ok(dict.unbind())
@@ -365,29 +365,29 @@ impl Connection {
let py = self_.py();
future_into_py(py, async move {
use lance_namespace::models::DropNamespaceRequest;
let mode_value = mode.and_then(|m| match m.to_uppercase().as_str() {
let mode_enum = mode.and_then(|m| match m.to_uppercase().as_str() {
"SKIP" => Some("Skip".to_string()),
"FAIL" => Some("Fail".to_string()),
_ => None,
});
let behavior_value = behavior.and_then(|b| match b.to_uppercase().as_str() {
let behavior_enum = behavior.and_then(|b| match b.to_uppercase().as_str() {
"RESTRICT" => Some("Restrict".to_string()),
"CASCADE" => Some("Cascade".to_string()),
_ => None,
});
let request = DropNamespaceRequest {
identity: None,
context: None,
id: if namespace.is_empty() {
None
} else {
Some(namespace)
},
mode: mode_value,
behavior: behavior_value,
mode: mode_enum,
behavior: behavior_enum,
..Default::default()
};
let response = inner.drop_namespace(request).await.infer_error()?;
Python::attach(|py| -> PyResult<Py<PyDict>> {
#[allow(deprecated)]
Python::with_gil(|py| -> PyResult<Py<PyDict>> {
let dict = PyDict::new(py);
dict.set_item("properties", response.properties)?;
dict.set_item("transaction_id", response.transaction_id)?;
@@ -406,16 +406,16 @@ impl Connection {
future_into_py(py, async move {
use lance_namespace::models::DescribeNamespaceRequest;
let request = DescribeNamespaceRequest {
identity: None,
context: None,
id: if namespace.is_empty() {
None
} else {
Some(namespace)
},
..Default::default()
};
let response = inner.describe_namespace(request).await.infer_error()?;
Python::attach(|py| -> PyResult<Py<PyDict>> {
#[allow(deprecated)]
Python::with_gil(|py| -> PyResult<Py<PyDict>> {
let dict = PyDict::new(py);
dict.set_item("properties", response.properties)?;
Ok(dict.unbind())
@@ -435,8 +435,6 @@ impl Connection {
future_into_py(py, async move {
use lance_namespace::models::ListTablesRequest;
let request = ListTablesRequest {
identity: None,
context: None,
id: if namespace.is_empty() {
None
} else {
@@ -444,9 +442,11 @@ impl Connection {
},
page_token,
limit: limit.map(|l| l as i32),
..Default::default()
};
let response = inner.list_tables(request).await.infer_error()?;
Python::attach(|py| -> PyResult<Py<PyDict>> {
#[allow(deprecated)]
Python::with_gil(|py| -> PyResult<Py<PyDict>> {
let dict = PyDict::new(py);
dict.set_item("tables", response.tables)?;
dict.set_item("page_token", response.page_token)?;

View File

@@ -40,31 +40,34 @@ impl<T> PythonErrorExt<T> for std::result::Result<T, LanceError> {
request_id,
source,
status_code,
} => Python::attach(|py| {
let message = err.to_string();
let http_err_cls = py
.import(intern!(py, "lancedb.remote.errors"))?
.getattr(intern!(py, "HttpError"))?;
let err = http_err_cls.call1((
message,
request_id,
status_code.map(|s| s.as_u16()),
))?;
if let Some(cause) = source.source() {
// The HTTP error already includes the first cause. But
// we can add the rest of the chain if there is any more.
let cause_err = http_from_rust_error(
py,
cause,
} => {
#[allow(deprecated)]
Python::with_gil(|py| {
let message = err.to_string();
let http_err_cls = py
.import(intern!(py, "lancedb.remote.errors"))?
.getattr(intern!(py, "HttpError"))?;
let err = http_err_cls.call1((
message,
request_id,
status_code.map(|s| s.as_u16()),
)?;
err.setattr(intern!(py, "__cause__"), cause_err)?;
}
))?;
Err(PyErr::from_value(err))
}),
if let Some(cause) = source.source() {
// The HTTP error already includes the first cause. But
// we can add the rest of the chain if there is any more.
let cause_err = http_from_rust_error(
py,
cause,
request_id,
status_code.map(|s| s.as_u16()),
)?;
err.setattr(intern!(py, "__cause__"), cause_err)?;
}
Err(PyErr::from_value(err))
})
}
LanceError::Retry {
request_id,
request_failures,
@@ -75,33 +78,37 @@ impl<T> PythonErrorExt<T> for std::result::Result<T, LanceError> {
max_read_failures,
source,
status_code,
} => Python::attach(|py| {
let cause_err = http_from_rust_error(
py,
source.as_ref(),
request_id,
status_code.map(|s| s.as_u16()),
)?;
} =>
{
#[allow(deprecated)]
Python::with_gil(|py| {
let cause_err = http_from_rust_error(
py,
source.as_ref(),
request_id,
status_code.map(|s| s.as_u16()),
)?;
let message = err.to_string();
let retry_error_cls = py
.import(intern!(py, "lancedb.remote.errors"))?
.getattr("RetryError")?;
let err = retry_error_cls.call1((
message,
request_id,
*request_failures,
*connect_failures,
*read_failures,
*max_request_failures,
*max_connect_failures,
*max_read_failures,
status_code.map(|s| s.as_u16()),
))?;
let message = err.to_string();
let retry_error_cls = py
.import(intern!(py, "lancedb.remote.errors"))?
.getattr("RetryError")?;
let err = retry_error_cls.call1((
message,
request_id,
*request_failures,
*connect_failures,
*read_failures,
*max_request_failures,
*max_connect_failures,
*max_read_failures,
status_code.map(|s| s.as_u16()),
))?;
err.setattr(intern!(py, "__cause__"), cause_err)?;
Err(PyErr::from_value(err))
}),
err.setattr(intern!(py, "__cause__"), cause_err)?;
Err(PyErr::from_value(err))
})
}
_ => self.runtime_error(),
},
}

View File

@@ -12,7 +12,8 @@ pub struct PyHeaderProvider {
impl Clone for PyHeaderProvider {
fn clone(&self) -> Self {
Python::attach(|py| Self {
#[allow(deprecated)]
Python::with_gil(|py| Self {
provider: self.provider.clone_ref(py),
})
}
@@ -25,7 +26,8 @@ impl PyHeaderProvider {
/// Get headers from the Python provider (internal implementation)
fn get_headers_internal(&self) -> Result<HashMap<String, String>, String> {
Python::attach(|py| {
#[allow(deprecated)]
Python::with_gil(|py| {
// Call the get_headers method
let result = self.provider.call_method0(py, "get_headers");

View File

@@ -19,7 +19,7 @@ use pyo3::{
exceptions::PyRuntimeError,
pyclass, pymethods,
types::{PyAnyMethods, PyDict, PyDictMethods, PyType},
Bound, PyAny, PyRef, PyRefMut, PyResult, Python,
Bound, Py, PyAny, PyRef, PyRefMut, PyResult, Python,
};
use pyo3_async_runtimes::tokio::future_into_py;
@@ -281,7 +281,12 @@ impl PyPermutationReader {
let reader = slf.reader.clone();
future_into_py(slf.py(), async move {
let schema = reader.output_schema(selection).await.infer_error()?;
Python::attach(|py| schema.as_ref().to_pyarrow(py).map(|obj| obj.unbind()))
#[allow(deprecated)]
let py_obj: Py<PyAny> = Python::with_gil(|py| -> PyResult<Py<PyAny>> {
let bound = schema.to_pyarrow(py)?;
Ok(bound.unbind())
})?;
Ok(py_obj)
})
}

View File

@@ -29,6 +29,7 @@ use pyo3::types::PyList;
use pyo3::types::{PyDict, PyString};
use pyo3::Bound;
use pyo3::IntoPyObject;
use pyo3::Py;
use pyo3::PyAny;
use pyo3::PyRef;
use pyo3::PyResult;
@@ -453,7 +454,12 @@ impl Query {
let inner = self_.inner.clone();
future_into_py(self_.py(), async move {
let schema = inner.output_schema().await.infer_error()?;
Python::attach(|py| schema.to_pyarrow(py).map(|obj| obj.unbind()))
#[allow(deprecated)]
let py_obj: Py<PyAny> = Python::with_gil(|py| -> PyResult<Py<PyAny>> {
let bound = schema.to_pyarrow(py)?;
Ok(bound.unbind())
})?;
Ok(py_obj)
})
}
@@ -532,7 +538,12 @@ impl TakeQuery {
let inner = self_.inner.clone();
future_into_py(self_.py(), async move {
let schema = inner.output_schema().await.infer_error()?;
Python::attach(|py| schema.to_pyarrow(py).map(|obj| obj.unbind()))
#[allow(deprecated)]
let py_obj: Py<PyAny> = Python::with_gil(|py| -> PyResult<Py<PyAny>> {
let bound = schema.to_pyarrow(py)?;
Ok(bound.unbind())
})?;
Ok(py_obj)
})
}
@@ -627,7 +638,12 @@ impl FTSQuery {
let inner = self_.inner.clone();
future_into_py(self_.py(), async move {
let schema = inner.output_schema().await.infer_error()?;
Python::attach(|py| schema.to_pyarrow(py).map(|obj| obj.unbind()))
#[allow(deprecated)]
let py_obj: Py<PyAny> = Python::with_gil(|py| -> PyResult<Py<PyAny>> {
let bound = schema.to_pyarrow(py)?;
Ok(bound.unbind())
})?;
Ok(py_obj)
})
}
@@ -806,7 +822,12 @@ impl VectorQuery {
let inner = self_.inner.clone();
future_into_py(self_.py(), async move {
let schema = inner.output_schema().await.infer_error()?;
Python::attach(|py| schema.to_pyarrow(py).map(|obj| obj.unbind()))
#[allow(deprecated)]
let py_obj: Py<PyAny> = Python::with_gil(|py| -> PyResult<Py<PyAny>> {
let bound = schema.to_pyarrow(py)?;
Ok(bound.unbind())
})?;
Ok(py_obj)
})
}

View File

@@ -22,7 +22,8 @@ pub struct PyStorageOptionsProvider {
impl Clone for PyStorageOptionsProvider {
fn clone(&self) -> Self {
Python::attach(|py| Self {
#[allow(deprecated)]
Python::with_gil(|py| Self {
inner: self.inner.clone_ref(py),
})
}
@@ -30,14 +31,17 @@ impl Clone for PyStorageOptionsProvider {
impl PyStorageOptionsProvider {
pub fn new(obj: Py<PyAny>) -> PyResult<Self> {
Python::attach(|py| {
#[allow(deprecated)]
Python::with_gil(|py| {
// Verify the object has a fetch_storage_options method
if !obj.bind(py).hasattr("fetch_storage_options")? {
return Err(pyo3::exceptions::PyTypeError::new_err(
"StorageOptionsProvider must implement fetch_storage_options() method",
));
}
Ok(Self { inner: obj })
Ok(Self {
inner: obj.clone_ref(py),
})
})
}
}
@@ -60,7 +64,8 @@ impl StorageOptionsProvider for PyStorageOptionsProviderWrapper {
let py_provider = self.py_provider.clone();
tokio::task::spawn_blocking(move || {
Python::attach(|py| {
#[allow(deprecated)]
Python::with_gil(|py| {
// Call the Python fetch_storage_options method
let result = py_provider
.inner
@@ -119,7 +124,8 @@ impl StorageOptionsProvider for PyStorageOptionsProviderWrapper {
}
fn provider_id(&self) -> String {
Python::attach(|py| {
#[allow(deprecated)]
Python::with_gil(|py| {
// Call provider_id() method on the Python object
let obj = self.py_provider.inner.bind(py);
obj.call_method0("provider_id")

View File

@@ -21,7 +21,7 @@ use pyo3::{
exceptions::{PyKeyError, PyRuntimeError, PyValueError},
pyclass, pymethods,
types::{IntoPyDict, PyAnyMethods, PyDict, PyDictMethods},
Bound, FromPyObject, PyAny, PyRef, PyResult, Python,
Bound, FromPyObject, Py, PyAny, PyRef, PyResult, Python,
};
use pyo3_async_runtimes::tokio::future_into_py;
@@ -287,7 +287,12 @@ impl Table {
let inner = self_.inner_ref()?.clone();
future_into_py(self_.py(), async move {
let schema = inner.schema().await.infer_error()?;
Python::attach(|py| schema.to_pyarrow(py).map(|obj| obj.unbind()))
#[allow(deprecated)]
let py_obj: Py<PyAny> = Python::with_gil(|py| -> PyResult<Py<PyAny>> {
let bound = schema.to_pyarrow(py)?;
Ok(bound.unbind())
})?;
Ok(py_obj)
})
}
@@ -437,7 +442,8 @@ impl Table {
future_into_py(self_.py(), async move {
let stats = inner.index_stats(&index_name).await.infer_error()?;
if let Some(stats) = stats {
Python::attach(|py| {
#[allow(deprecated)]
Python::with_gil(|py| {
let dict = PyDict::new(py);
dict.set_item("num_indexed_rows", stats.num_indexed_rows)?;
dict.set_item("num_unindexed_rows", stats.num_unindexed_rows)?;
@@ -467,7 +473,8 @@ impl Table {
let inner = self_.inner_ref()?.clone();
future_into_py(self_.py(), async move {
let stats = inner.stats().await.infer_error()?;
Python::attach(|py| {
#[allow(deprecated)]
Python::with_gil(|py| {
let dict = PyDict::new(py);
dict.set_item("total_bytes", stats.total_bytes)?;
dict.set_item("num_rows", stats.num_rows)?;
@@ -516,7 +523,8 @@ impl Table {
let inner = self_.inner_ref()?.clone();
future_into_py(self_.py(), async move {
let versions = inner.list_versions().await.infer_error()?;
let versions_as_dict = Python::attach(|py| {
#[allow(deprecated)]
let versions_as_dict = Python::with_gil(|py| {
versions
.iter()
.map(|v| {
@@ -867,7 +875,8 @@ impl Tags {
let tags = inner.tags().await.infer_error()?;
let res = tags.list().await.infer_error()?;
Python::attach(|py| {
#[allow(deprecated)]
Python::with_gil(|py| {
let py_dict = PyDict::new(py);
for (key, contents) in res {
let value_dict = PyDict::new(py);

View File

@@ -134,11 +134,10 @@ impl Database for LanceNamespaceDatabase {
async fn table_names(&self, request: TableNamesRequest) -> Result<Vec<String>> {
let ns_request = ListTablesRequest {
identity: None,
context: None,
id: Some(request.namespace),
page_token: request.start_after,
limit: request.limit.map(|l| l as i32),
..Default::default()
};
let response = self.namespace.list_tables(ns_request).await?;
@@ -154,13 +153,9 @@ impl Database for LanceNamespaceDatabase {
let mut table_id = request.namespace.clone();
table_id.push(request.name.clone());
let describe_request = DescribeTableRequest {
identity: None,
context: None,
id: Some(table_id.clone()),
version: None,
with_table_uri: None,
load_detailed_metadata: None,
vend_credentials: None,
..Default::default()
};
let describe_result = self.namespace.describe_table(describe_request).await;
@@ -177,9 +172,8 @@ impl Database for LanceNamespaceDatabase {
if describe_result.is_ok() {
// Drop the existing table - must succeed
let drop_request = DropTableRequest {
identity: None,
context: None,
id: Some(table_id.clone()),
..Default::default()
};
self.namespace
.drop_table(drop_request)
@@ -212,15 +206,10 @@ impl Database for LanceNamespaceDatabase {
table_id.push(request.name.clone());
let create_empty_request = DeclareTableRequest {
identity: None,
context: None,
id: Some(table_id.clone()),
location: None,
vend_credentials: if self.storage_options.is_empty() {
None
} else {
Some(true)
},
vend_credentials: None,
..Default::default()
};
let create_empty_response = self
@@ -293,9 +282,8 @@ impl Database for LanceNamespaceDatabase {
table_id.push(name.to_string());
let drop_request = DropTableRequest {
identity: None,
context: None,
id: Some(table_id),
..Default::default()
};
self.namespace
.drop_table(drop_request)
@@ -450,11 +438,10 @@ mod tests {
// Create a child namespace first
conn.create_namespace(CreateNamespaceRequest {
identity: None,
context: None,
id: Some(vec!["test_ns".into()]),
mode: None,
properties: None,
..Default::default()
})
.await
.expect("Failed to create namespace");
@@ -513,11 +500,10 @@ mod tests {
// Create a child namespace first
conn.create_namespace(CreateNamespaceRequest {
identity: None,
context: None,
id: Some(vec!["test_ns".into()]),
mode: None,
properties: None,
..Default::default()
})
.await
.expect("Failed to create namespace");
@@ -579,11 +565,10 @@ mod tests {
// Create a child namespace first
conn.create_namespace(CreateNamespaceRequest {
identity: None,
context: None,
id: Some(vec!["test_ns".into()]),
mode: None,
properties: None,
..Default::default()
})
.await
.expect("Failed to create namespace");
@@ -665,11 +650,10 @@ mod tests {
// Create a child namespace first
conn.create_namespace(CreateNamespaceRequest {
identity: None,
context: None,
id: Some(vec!["test_ns".into()]),
mode: None,
properties: None,
..Default::default()
})
.await
.expect("Failed to create namespace");
@@ -723,11 +707,10 @@ mod tests {
// Create a child namespace first
conn.create_namespace(CreateNamespaceRequest {
identity: None,
context: None,
id: Some(vec!["test_ns".into()]),
mode: None,
properties: None,
..Default::default()
})
.await
.expect("Failed to create namespace");
@@ -806,11 +789,10 @@ mod tests {
// Create a child namespace first
conn.create_namespace(CreateNamespaceRequest {
identity: None,
context: None,
id: Some(vec!["test_ns".into()]),
mode: None,
properties: None,
..Default::default()
})
.await
.expect("Failed to create namespace");
@@ -842,11 +824,10 @@ mod tests {
// Create a child namespace first
conn.create_namespace(CreateNamespaceRequest {
identity: None,
context: None,
id: Some(vec!["test_ns".into()]),
mode: None,
properties: None,
..Default::default()
})
.await
.expect("Failed to create namespace");

View File

@@ -54,6 +54,8 @@
//! You can also use [`ConnectOptions`] to configure the connection to the database.
//!
//! ```rust
//! # #[cfg(feature = "aws")]
//! # {
//! use object_store::aws::AwsCredential;
//! # tokio::runtime::Runtime::new().unwrap().block_on(async {
//! let db = lancedb::connect("data/sample-lancedb")
@@ -66,6 +68,7 @@
//! .await
//! .unwrap();
//! # });
//! # }
//! ```
//!
//! LanceDB uses [arrow-rs](https://github.com/apache/arrow-rs) to define schema, data types and array itself.

View File

@@ -1717,11 +1717,10 @@ mod tests {
// Create a child namespace first
let namespace = vec!["test_ns".to_string()];
conn.create_namespace(CreateNamespaceRequest {
identity: None,
context: None,
id: Some(namespace.clone()),
mode: None,
properties: None,
..Default::default()
})
.await
.expect("Failed to create namespace");
@@ -1745,11 +1744,10 @@ mod tests {
// List tables in the child namespace
let list_response = conn
.list_tables(ListTablesRequest {
identity: None,
context: None,
id: Some(namespace.clone()),
page_token: None,
limit: None,
..Default::default()
})
.await
.expect("Failed to list tables");
@@ -1759,11 +1757,10 @@ mod tests {
let namespace_client = conn.namespace_client().await.unwrap();
let list_response = namespace_client
.list_tables(ListTablesRequest {
identity: None,
context: None,
id: Some(namespace.clone()),
page_token: None,
limit: None,
..Default::default()
})
.await
.unwrap();
@@ -1802,11 +1799,10 @@ mod tests {
// Create a child namespace first
let namespace = vec!["multi_table_ns".to_string()];
conn.create_namespace(CreateNamespaceRequest {
identity: None,
context: None,
id: Some(namespace.clone()),
mode: None,
properties: None,
..Default::default()
})
.await
.expect("Failed to create namespace");
@@ -1830,11 +1826,10 @@ mod tests {
// List tables in the child namespace
let list_response = conn
.list_tables(ListTablesRequest {
identity: None,
context: None,
id: Some(namespace.clone()),
page_token: None,
limit: None,
..Default::default()
})
.await
.unwrap();

View File

@@ -1425,7 +1425,7 @@ impl Table {
.collect::<Vec<_>>();
let unioned = UnionExec::try_new(projected_plans).map_err(|e| Error::Runtime {
message: format!("Failed to union query plans: {}", e),
message: format!("Failed to build union plan: {e}"),
})?;
// We require 1 partition in the final output
let repartitioned = RepartitionExec::try_new(
@@ -2348,7 +2348,7 @@ impl NativeTable {
};
// Convert select to columns list
let columns = match &vq.base.select {
let columns: Option<Box<QueryTableRequestColumns>> = match &vq.base.select {
Select::All => None,
Select::Columns(cols) => Some(Box::new(QueryTableRequestColumns {
column_names: Some(cols.clone()),
@@ -2388,8 +2388,6 @@ impl NativeTable {
});
Ok(NsQueryTableRequest {
identity: None,
context: None,
id: None, // Will be set in namespace_query
k: vq.base.limit.unwrap_or(10) as i32,
vector: Box::new(vector),
@@ -2409,6 +2407,7 @@ impl NativeTable {
bypass_vector_index: Some(!vq.use_index),
full_text_query,
version: None,
..Default::default()
})
}
AnyQuery::Query(q) => {
@@ -2426,7 +2425,7 @@ impl NativeTable {
.map(|f| self.filter_to_sql(f))
.transpose()?;
let columns = match &q.select {
let columns: Option<Box<QueryTableRequestColumns>> = match &q.select {
Select::All => None,
Select::Columns(cols) => Some(Box::new(QueryTableRequestColumns {
column_names: Some(cols.clone()),
@@ -2463,8 +2462,6 @@ impl NativeTable {
});
Ok(NsQueryTableRequest {
identity: None,
context: None,
id: None, // Will be set by caller
vector,
k: q.limit.unwrap_or(10) as i32,
@@ -2484,6 +2481,7 @@ impl NativeTable {
fast_search: None,
lower_bound: None,
upper_bound: None,
..Default::default()
})
}
}
@@ -5155,16 +5153,15 @@ mod tests {
let any_query = AnyQuery::VectorQuery(vq);
let ns_request = table.convert_to_namespace_query(&any_query).unwrap();
let column_names = ns_request
.columns
.as_ref()
.and_then(|cols| cols.column_names.clone());
assert_eq!(ns_request.k, 10);
assert_eq!(ns_request.offset, Some(5));
assert_eq!(ns_request.filter, Some("id > 0".to_string()));
assert_eq!(
ns_request
.columns
.as_ref()
.and_then(|columns| columns.column_names.clone()),
Some(vec!["id".to_string()])
);
assert_eq!(column_names, Some(vec!["id".to_string()]));
assert_eq!(ns_request.vector_column, Some("vector".to_string()));
assert_eq!(ns_request.distance_type, Some("l2".to_string()));
assert!(ns_request.vector.single_vector.is_some());
@@ -5201,17 +5198,16 @@ mod tests {
let any_query = AnyQuery::Query(q);
let ns_request = table.convert_to_namespace_query(&any_query).unwrap();
let column_names = ns_request
.columns
.as_ref()
.and_then(|cols| cols.column_names.clone());
// Plain queries should pass an empty vector
assert_eq!(ns_request.k, 20);
assert_eq!(ns_request.offset, Some(5));
assert_eq!(ns_request.filter, Some("id > 5".to_string()));
assert_eq!(
ns_request
.columns
.as_ref()
.and_then(|columns| columns.column_names.clone()),
Some(vec!["id".to_string()])
);
assert_eq!(column_names, Some(vec!["id".to_string()]));
assert_eq!(ns_request.with_row_id, Some(true));
assert_eq!(ns_request.bypass_vector_index, Some(true));
assert!(ns_request.vector_column.is_none()); // No vector column for plain queries

View File

@@ -100,8 +100,8 @@ impl DatasetRef {
let should_checkout = match &target_ref {
refs::Ref::Version(_, Some(target_ver)) => version != target_ver,
refs::Ref::Version(_, None) => true, // No specific version, always checkout
refs::Ref::Tag(_) => true, // Always checkout for tags
refs::Ref::VersionNumber(target_ver) => version != target_ver,
refs::Ref::Tag(_) => true, // Always checkout for tags
};
if should_checkout {