This is an automated email from the ASF dual-hosted git repository.

JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new 53d3fa6443 [python][daft] Fix single-part catalog table lookup (#8039)
53d3fa6443 is described below

commit 53d3fa6443a7c7cd7b0e6dfccd6332fc7f14faaf
Author: QuakeWang <[email protected]>
AuthorDate: Sat May 30 23:13:36 2026 +0800

    [python][daft] Fix single-part catalog table lookup (#8039)
    
    Daft Catalog accepts single-part identifiers, and PaimonCatalog
    previously forwarded them to pypaimon as plain table names. For table
    APIs, this is invalid because pypaimon's Identifier parser
    requires `db.table`, so `get_table("missing_table")` and
    `drop_table("missing_table")` leaked `ValueError` instead of Daft
    `NotFoundError`.
    
    This PR adds table-specific identifier handling in `PaimonCatalog`:
    single-part table identifiers are handled at the Daft catalog layer as
    not found, and `has_table("missing_table")` now returns `False`.
---
 paimon-python/pypaimon/daft/daft_catalog.py        | 26 ++++++++++++++++++----
 .../pypaimon/tests/daft/daft_catalog_test.py       | 17 ++++++++++++++
 2 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/paimon-python/pypaimon/daft/daft_catalog.py 
b/paimon-python/pypaimon/daft/daft_catalog.py
index aaf3f6879d..2cbe479b81 100644
--- a/paimon-python/pypaimon/daft/daft_catalog.py
+++ b/paimon-python/pypaimon/daft/daft_catalog.py
@@ -115,7 +115,9 @@ class PaimonCatalog(Catalog):
             raise NotFoundError(f"Namespace '{db_name}' not found.") from ex
 
     def _drop_table(self, ident: Identifier) -> None:
-        paimon_ident = _to_paimon_ident(ident)
+        paimon_ident = _to_paimon_table_ident(ident)
+        if paimon_ident is None:
+            raise NotFoundError(f"Table '{ident}' not found.")
         try:
             self._inner.drop_table(paimon_ident, ignore_if_not_exists=False)
         except TableNotExistException as ex:
@@ -134,7 +136,9 @@ class PaimonCatalog(Catalog):
             return False
 
     def _has_table(self, ident: Identifier) -> bool:
-        paimon_ident = _to_paimon_ident(ident)
+        paimon_ident = _to_paimon_table_ident(ident)
+        if paimon_ident is None:
+            return False
         try:
             self._inner.get_table(paimon_ident)
             return True
@@ -149,7 +153,9 @@ class PaimonCatalog(Catalog):
         raise NotFoundError(f"Function '{ident}' not found in catalog 
'{self.name}'")
 
     def _get_table(self, ident: Identifier) -> PaimonTable:
-        paimon_ident = _to_paimon_ident(ident)
+        paimon_ident = _to_paimon_table_ident(ident)
+        if paimon_ident is None:
+            raise NotFoundError(f"Table '{ident}' not found.")
         try:
             inner = self._inner.get_table(paimon_ident)
             return PaimonTable(inner, catalog_options=self._catalog_options)
@@ -250,7 +256,7 @@ class PaimonTable(Table):
 def _to_paimon_ident(ident: Identifier) -> str:
     """Convert a Daft identifier to a pypaimon identifier string.
 
-    - 1 part  (table,)              -> 'table'
+    - 1 part  (namespace/table,)    -> 'namespace_or_table'
     - 2 parts (db, table)           -> 'db.table'
     - 3 parts (catalog, db, table)  -> 'db.table'  (catalog prefix stripped)
     """
@@ -264,6 +270,18 @@ def _to_paimon_ident(ident: Identifier) -> str:
     return ident
 
 
+def _to_paimon_table_ident(ident: Identifier) -> str | None:
+    """Convert a Daft table identifier to Paimon's required db.table form."""
+    if isinstance(ident, Identifier):
+        parts = tuple(ident)
+        if len(parts) == 3:
+            return f"{parts[1]}.{parts[2]}"
+        if len(parts) == 2:
+            return f"{parts[0]}.{parts[1]}"
+        return None
+    return ident
+
+
 def _cast_large_types(arrow_schema: pa.Schema) -> pa.Schema:
     """Convert PyArrow schema to be compatible with pypaimon.
 
diff --git a/paimon-python/pypaimon/tests/daft/daft_catalog_test.py 
b/paimon-python/pypaimon/tests/daft/daft_catalog_test.py
index 0b34452ed4..95519aa3be 100644
--- a/paimon-python/pypaimon/tests/daft/daft_catalog_test.py
+++ b/paimon-python/pypaimon/tests/daft/daft_catalog_test.py
@@ -156,6 +156,7 @@ def test_catalog_has_table(paimon_catalog):
     assert daft_catalog.has_table("test_db.test_table")
     assert not daft_catalog.has_table("test_db.nonexistent_table")
     assert not daft_catalog.has_table("nonexistent_db.test_table")
+    assert not daft_catalog.has_table("missing_table")
 
 
 def test_catalog_list_tables(paimon_catalog):
@@ -188,6 +189,14 @@ def test_catalog_get_table_not_found(paimon_catalog):
         daft_catalog.get_table("test_db.nonexistent_table")
 
 
+def test_catalog_get_table_single_part_not_found(paimon_catalog):
+    from daft.catalog import NotFoundError
+
+    daft_catalog, _, _ = paimon_catalog
+    with pytest.raises(NotFoundError):
+        daft_catalog.get_table("missing_table")
+
+
 def test_catalog_drop_table(paimon_catalog):
     daft_catalog, _, _ = paimon_catalog
     assert daft_catalog.has_table("test_db.test_table")
@@ -195,6 +204,14 @@ def test_catalog_drop_table(paimon_catalog):
     assert not daft_catalog.has_table("test_db.test_table")
 
 
+def test_catalog_drop_table_single_part_not_found(paimon_catalog):
+    from daft.catalog import NotFoundError
+
+    daft_catalog, _, _ = paimon_catalog
+    with pytest.raises(NotFoundError):
+        daft_catalog.drop_table("missing_table")
+
+
 def test_catalog_create_table(tmp_path):
     inner = pypaimon.CatalogFactory.create({"warehouse": str(tmp_path)})
     inner.create_database("mydb", ignore_if_exists=True)

Reply via email to