feat: support opening a branch directly via open_table

This commit is contained in:
Brendan Clement
2026-06-02 22:40:13 -07:00
parent c13c3184cf
commit 38454969cd
7 changed files with 108 additions and 15 deletions

View File

@@ -416,6 +416,7 @@ class DBConnection(EnforceOverrides):
namespace_path: Optional[List[str]] = None,
storage_options: Optional[Dict[str, str]] = None,
index_cache_size: Optional[int] = None,
branch: Optional[str] = None,
) -> Table:
"""Open a Lance Table in the database.
@@ -444,6 +445,9 @@ class DBConnection(EnforceOverrides):
connection will be inherited by the table, but can be overridden here.
See available options at
<https://docs.lancedb.com/storage/>
branch: str, optional
If provided, open a handle scoped to this branch instead of the
default branch. Reads and writes operate in the branch's context.
Returns
-------
@@ -958,6 +962,7 @@ class LanceDBConnection(DBConnection):
namespace_path: Optional[List[str]] = None,
storage_options: Optional[Dict[str, str]] = None,
index_cache_size: Optional[int] = None,
branch: Optional[str] = None,
) -> LanceTable:
"""Open a table in the database.
@@ -968,6 +973,9 @@ class LanceDBConnection(DBConnection):
namespace_path: List[str], optional
The namespace to open the table from. When non-empty, the
table is resolved through the directory namespace client.
branch: str, optional
If provided, open a handle scoped to this branch instead of the
default branch. Reads and writes operate in the branch's context.
Returns
-------
@@ -987,20 +995,24 @@ class LanceDBConnection(DBConnection):
)
if namespace_path:
return self._namespace_conn().open_table(
tbl = self._namespace_conn().open_table(
name,
namespace_path=namespace_path,
storage_options=storage_options,
index_cache_size=index_cache_size,
)
else:
tbl = LanceTable.open(
self,
name,
namespace_path=namespace_path,
storage_options=storage_options,
index_cache_size=index_cache_size,
)
return LanceTable.open(
self,
name,
namespace_path=namespace_path,
storage_options=storage_options,
index_cache_size=index_cache_size,
)
if branch is not None:
return tbl.branches.checkout(branch)
return tbl
def clone_table(
self,
@@ -1641,6 +1653,7 @@ class AsyncConnection(object):
location: Optional[str] = None,
namespace_client: Optional[Any] = None,
managed_versioning: Optional[bool] = None,
branch: Optional[str] = None,
) -> AsyncTable:
"""Open a Lance Table in the database.
@@ -1676,6 +1689,9 @@ class AsyncConnection(object):
managed_versioning: bool, optional
Whether managed versioning is enabled for this table. If provided,
avoids a redundant describe_table call when namespace_client is set.
branch: str, optional
If provided, open a handle scoped to this branch instead of the
default branch. Reads and writes operate in the branch's context.
Returns
-------
@@ -1692,7 +1708,10 @@ class AsyncConnection(object):
namespace_client=namespace_client,
managed_versioning=managed_versioning,
)
return AsyncTable(table)
tbl = AsyncTable(table)
if branch is not None:
return await tbl.branches.checkout(branch)
return tbl
async def clone_table(
self,

View File

@@ -952,6 +952,23 @@ def test_branches_preserve_namespace(tmp_path):
assert branch.id == table.id
def test_open_table_with_branch(tmp_path):
db = lancedb.connect(tmp_path)
table = db.create_table("t", [{"i": 1}])
table.branches.create("exp").add([{"i": 2}])
# open_table(branch=...) returns a handle scoped to the branch
assert db.open_table("t", branch="exp").count_rows() == 2
# opening without branch still tracks main
assert db.open_table("t").count_rows() == 1
# with a namespace, the opened branch handle preserves namespace identity
nt = db.create_table("ns_t", [{"i": 1}], namespace_path=["ns1"])
nt.branches.create("exp")
opened = db.open_table("ns_t", namespace_path=["ns1"], branch="exp")
assert opened.namespace == ["ns1"]
@pytest.mark.asyncio
async def test_async_branches(tmp_path):
db = await lancedb.connect_async(tmp_path)