mirror of
https://github.com/lancedb/lancedb.git
synced 2026-10-12 14:52:26 +00:00
fix(python): support exist_ok in local create_table (#4421)
Synchronous local Python `create_table` callers using `mode="exist_ok"` received `ValueError` instead of creating or opening a table. Related to [#2900](https://github.com/lancedb/lancedb/issues/2900). The local wrapper rejected this mode before the shared Rust parser could validate it. Removing that guard delegates mode validation to the parser, and the sync and async docs now describe `exist_ok`. Remote option gaps and the TypeScript table type gap remain outside this change. The added tests retain both calls from [@wjones127's comment](https://github.com/lancedb/lancedb/issues/2900#issuecomment-5964167206). This builds on the code @wjones127 posted there. Three regression tests fail before the change, pass after it, fail with the original `db.py` restored, then pass again on HEAD. Tested on Linux x86_64 with Python 3.14.7. From the Python directory, `uv run --no-sync --extra tests --extra dev python -m pytest python/tests/test_db.py -q` reports 53 passed. `uv run --no-sync --extra tests --extra dev python -m pytest python/tests -q -rs -m "not slow and not s3_test"` reports 1428 passed, 34 skipped, 68 deselected, and one failure: the existing `test_get_lsm_write_spec`, also failing on clean base (1425 passed, one failed). Ruff 0.9.9 `ruff format --check .` and `ruff check .` pass. Tests used worktree Python code with the released `lancedb==0.40.0b12` native wheel. No native source build was run. Co-authored-by: Will Jones <willjones127@gmail.com>
This commit is contained in:
co-authored by
Will Jones
parent
9c3e1cbae7
commit
0be3ae960e
@@ -409,9 +409,10 @@ class DBConnection(EnforceOverrides):
|
||||
- [LanceModel][lancedb.pydantic.LanceModel]
|
||||
mode: str; default "create"
|
||||
The mode to use when creating the table.
|
||||
Can be either "create" or "overwrite".
|
||||
Can be "create", "overwrite", or "exist_ok".
|
||||
By default, if the table already exists, an exception is raised.
|
||||
If you want to overwrite the table, use mode="overwrite".
|
||||
To open an existing table without adding data, use mode="exist_ok".
|
||||
exist_ok: bool, default False
|
||||
If a table by the same name already exists, then raise an exception
|
||||
if exist_ok=False. If exist_ok=True, then open the existing table;
|
||||
@@ -1546,8 +1547,6 @@ class LanceDBConnection(DBConnection):
|
||||
"""
|
||||
if namespace_path is None:
|
||||
namespace_path = []
|
||||
if mode.lower() not in ["create", "overwrite"]:
|
||||
raise ValueError("mode must be either 'create' or 'overwrite'")
|
||||
validate_table_name(name)
|
||||
|
||||
tbl = LanceTable.create(
|
||||
@@ -2350,11 +2349,12 @@ class AsyncConnection(object):
|
||||
- pyarrow.Schema
|
||||
|
||||
- [LanceModel][lancedb.pydantic.LanceModel]
|
||||
mode: Literal["create", "overwrite"]; default "create"
|
||||
mode: Literal["create", "overwrite", "exist_ok"]; default "create"
|
||||
The mode to use when creating the table.
|
||||
Can be either "create" or "overwrite".
|
||||
Can be "create", "overwrite", or "exist_ok".
|
||||
By default, if the table already exists, an exception is raised.
|
||||
If you want to overwrite the table, use mode="overwrite".
|
||||
To open an existing table without adding data, use mode="exist_ok".
|
||||
exist_ok: bool, default False
|
||||
If a table by the same name already exists, then raise an exception
|
||||
if exist_ok=False. If exist_ok=True, then open the existing table;
|
||||
|
||||
@@ -351,6 +351,40 @@ async def test_create_table_from_iterator_async(mem_db_async: lancedb.AsyncConne
|
||||
assert await table.count_rows() == 10
|
||||
|
||||
|
||||
def test_create_exist_ok_mode(tmp_db: lancedb.DBConnection):
|
||||
db = tmp_db
|
||||
data = [{"vector": [1.1, 1.2]}, {"vector": [0.2, 1.8]}]
|
||||
table = db.create_table("t1", data, mode="exist_ok")
|
||||
assert table.count_rows() == 2
|
||||
original = table.to_arrow()
|
||||
|
||||
reopened = db.create_table("t1", [{"vector": [9.0, 8.0]}], mode="exist_ok")
|
||||
assert reopened.to_arrow().equals(original)
|
||||
|
||||
|
||||
def test_create_empty_exist_ok_mode(tmp_db: lancedb.DBConnection):
|
||||
schema = pa.schema([pa.field("id", pa.int64())])
|
||||
table = tmp_db.create_table("empty", schema=schema, mode="exist_ok")
|
||||
assert table.schema == schema
|
||||
assert table.count_rows() == 0
|
||||
table.add([{"id": 7}])
|
||||
|
||||
reopened = tmp_db.create_table("empty", schema=schema, mode="exist_ok")
|
||||
assert reopened.to_arrow().to_pylist() == [{"id": 7}]
|
||||
|
||||
bad_schema = pa.schema([pa.field("other", pa.int64())])
|
||||
with pytest.raises(ValueError):
|
||||
tmp_db.create_table("empty", schema=bad_schema, mode="exist_ok")
|
||||
|
||||
|
||||
def test_create_table_invalid_mode(tmp_db: lancedb.DBConnection):
|
||||
db = tmp_db
|
||||
data = [{"vector": [1.1, 1.2]}, {"vector": [0.2, 1.8]}]
|
||||
with pytest.raises(ValueError, match="Invalid mode bogus"):
|
||||
db.create_table("tb", data, mode="bogus")
|
||||
assert "tb" not in db
|
||||
|
||||
|
||||
def test_create_exist_ok(tmp_db: lancedb.DBConnection):
|
||||
from conftest import pandas_string_type
|
||||
|
||||
|
||||
Reference in New Issue
Block a user