mirror of
https://github.com/lancedb/lancedb.git
synced 2026-10-26 05:26:14 +00:00
fix: validate Python read consistency intervals (#4454)
Negative `read_consistency_interval` values currently reach Rust's
panicking `Duration::from_secs_f64` conversion. For example:
```python
from datetime import timedelta
import lancedb
lancedb.connect("./db", read_consistency_interval=timedelta(seconds=-1))
```
Validate the interval with `Duration::try_from_secs_f64` at the three
native connection entry points and return `ValueError` before
constructing the connection or async future. `None`, zero and positive
intervals retain their behavior. The raw native binding also rejects
NaN, infinity and overflow; the public Python API still accepts
`timedelta`, not floats.
Tests cover public sync/async connections, native namespace connections,
real Python namespace clients, the three raw binding entry points and
valid-value controls.
Validation on Python 3.12 / Rust 1.97:
- Same 26 regression cases against separately built native baseline and
candidate: baseline 22 failed / 4 passed; candidate 26 passed.
- Existing basic connection and background-loop regression tests pass.
- `cargo fmt --all -- --check`, Ruff check/format and `git diff --check`
pass.
The native builds used the unchanged repository `ci` profile and
Cargo.lock with `--no-default-features --features
remote,lancedb/metrics-otel,pyo3/extension-module`. Python runtime and
focused test dependency versions came from `python/uv.lock`. Source-tree
tests used a minimal distribution-version metadata fixture derived from
the unchanged Cargo/pyproject manifests; both imported module origins
and native versions were checked in fresh processes. This is not a
complete Maturin packaging, cloud backend or full Python suite result.
No GPU was used.
AI-assisted diagnosis, implementation and validation.
Signed-off-by: Xucheng Zhou <aden1350@outlook.com>
This commit is contained in:
@@ -49,6 +49,18 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_read_consistency_interval(interval: Option<f64>) -> PyResult<Option<Duration>> {
|
||||
interval
|
||||
.map(|seconds| {
|
||||
Duration::try_from_secs_f64(seconds).map_err(|_| {
|
||||
PyValueError::new_err(
|
||||
"read_consistency_interval must be finite, non-negative, and within the supported range",
|
||||
)
|
||||
})
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
fn parse_namespace_client_pushdown_operations(
|
||||
operations: Option<Vec<String>>,
|
||||
) -> PyResult<HashSet<NamespaceClientPushdownOperation>> {
|
||||
@@ -1077,6 +1089,7 @@ pub fn connect(
|
||||
namespace_client_properties: Option<HashMap<String, String>>,
|
||||
oauth_config: Option<crate::oauth::PyOAuthConfig>,
|
||||
) -> PyResult<Bound<'_, PyAny>> {
|
||||
let read_consistency_interval = parse_read_consistency_interval(read_consistency_interval)?;
|
||||
future_into_py(py, async move {
|
||||
let mut builder = lancedb::connect(&uri);
|
||||
if let Some(api_key) = api_key {
|
||||
@@ -1095,7 +1108,6 @@ pub fn connect(
|
||||
#[cfg(not(feature = "remote"))]
|
||||
let _ = sql_host_override;
|
||||
if let Some(read_consistency_interval) = read_consistency_interval {
|
||||
let read_consistency_interval = Duration::from_secs_f64(read_consistency_interval);
|
||||
builder = builder.read_consistency_interval(read_consistency_interval);
|
||||
}
|
||||
if let Some(storage_options) = storage_options {
|
||||
@@ -1144,7 +1156,7 @@ pub fn connect_namespace_client(
|
||||
namespace_client_impl: Option<String>,
|
||||
namespace_client_properties: Option<HashMap<String, String>>,
|
||||
) -> PyResult<Connection> {
|
||||
let read_consistency_interval = read_consistency_interval.map(Duration::from_secs_f64);
|
||||
let read_consistency_interval = parse_read_consistency_interval(read_consistency_interval)?;
|
||||
let namespace_client_pushdown_operations =
|
||||
parse_namespace_client_pushdown_operations(namespace_client_pushdown_operations)?;
|
||||
let ns_properties = namespace_client_properties.unwrap_or_default();
|
||||
@@ -1201,7 +1213,7 @@ pub fn connect_namespace(
|
||||
session: Option<crate::session::Session>,
|
||||
namespace_client_pushdown_operations: Option<Vec<String>>,
|
||||
) -> PyResult<Connection> {
|
||||
let read_consistency_interval = read_consistency_interval.map(Duration::from_secs_f64);
|
||||
let read_consistency_interval = parse_read_consistency_interval(read_consistency_interval)?;
|
||||
let namespace_client_pushdown_operations =
|
||||
parse_namespace_client_pushdown_operations(namespace_client_pushdown_operations)?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user