You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@paimon.apache.org by lz...@apache.org on 2026/03/09 04:01:33 UTC

(paimon) branch master updated: [python] Introduce catalog list-dbs in Python CLI (#7366)

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

lzljs3620320 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 5e0859d0f8 [python] Introduce catalog list-dbs in Python CLI (#7366)
5e0859d0f8 is described below

commit 5e0859d0f8f51771304813f3534ce1aef96422ec
Author: Jingsong Lee <ji...@gmail.com>
AuthorDate: Mon Mar 9 12:01:27 2026 +0800

    [python] Introduce catalog list-dbs in Python CLI (#7366)
    
    List all databases in the catalog.
    
    ```shell
    paimon catalog list-dbs
    ```
    
    Output:
    ```
    default
    mydb
    analytics
    ```
---
 docs/content/pypaimon/cli.md                       | 17 ++++++
 paimon-python/pypaimon/catalog/catalog.py          |  4 ++
 .../pypaimon/catalog/filesystem_catalog.py         | 11 ++++
 paimon-python/pypaimon/cli/cli.py                  |  7 +++
 paimon-python/pypaimon/cli/cli_catalog.py          | 65 ++++++++++++++++++++++
 paimon-python/pypaimon/tests/cli_db_test.py        | 33 +++++++++++
 6 files changed, 137 insertions(+)

diff --git a/docs/content/pypaimon/cli.md b/docs/content/pypaimon/cli.md
index 3bd3859e2c..5ee86b34e4 100644
--- a/docs/content/pypaimon/cli.md
+++ b/docs/content/pypaimon/cli.md
@@ -445,3 +445,20 @@ orders
 products
 users
 ```
+
+## Catalog Commands
+
+### Catalog List DBs
+
+List all databases in the catalog.
+
+```shell
+paimon catalog list-dbs
+```
+
+Output:
+```
+default
+mydb
+analytics
+```
diff --git a/paimon-python/pypaimon/catalog/catalog.py b/paimon-python/pypaimon/catalog/catalog.py
index 36434ca7ab..2cca595411 100644
--- a/paimon-python/pypaimon/catalog/catalog.py
+++ b/paimon-python/pypaimon/catalog/catalog.py
@@ -39,6 +39,10 @@ class Catalog(ABC):
     COMMENT_PROP = "comment"
     OWNER_PROP = "owner"
 
+    @abstractmethod
+    def list_databases(self) -> List[str]:
+        """List all database names in the catalog."""
+
     @abstractmethod
     def get_database(self, name: str) -> 'Database':
         """Get paimon database identified by the given name."""
diff --git a/paimon-python/pypaimon/catalog/filesystem_catalog.py b/paimon-python/pypaimon/catalog/filesystem_catalog.py
index c4cea918c1..eb8fea5ba0 100644
--- a/paimon-python/pypaimon/catalog/filesystem_catalog.py
+++ b/paimon-python/pypaimon/catalog/filesystem_catalog.py
@@ -48,6 +48,17 @@ class FileSystemCatalog(Catalog):
         self.catalog_options = catalog_options
         self.file_io = FileIO.get(self.warehouse, self.catalog_options)
 
+    def list_databases(self) -> list:
+        statuses = self.file_io.list_status(self.warehouse)
+        database_names = []
+        for status in statuses:
+            import pyarrow.fs as pafs
+            is_directory = hasattr(status, 'type') and status.type == pafs.FileType.Directory
+            name = status.base_name if hasattr(status, 'base_name') else ""
+            if is_directory and name and name.endswith(Catalog.DB_SUFFIX):
+                database_names.append(name[:-len(Catalog.DB_SUFFIX)])
+        return sorted(database_names)
+
     def get_database(self, name: str) -> Database:
         if self.file_io.exists(self.get_database_path(name)):
             return Database(name, {})
diff --git a/paimon-python/pypaimon/cli/cli.py b/paimon-python/pypaimon/cli/cli.py
index 50b882d2e5..2ffdbd206d 100644
--- a/paimon-python/pypaimon/cli/cli.py
+++ b/paimon-python/pypaimon/cli/cli.py
@@ -114,6 +114,13 @@ def main():
     from pypaimon.cli.cli_db import add_db_subcommands
     add_db_subcommands(db_parser)
 
+    # Catalog commands
+    catalog_parser = subparsers.add_parser('catalog', help='Catalog operations')
+
+    # Import and add catalog subcommands
+    from pypaimon.cli.cli_catalog import add_catalog_subcommands
+    add_catalog_subcommands(catalog_parser)
+
     args = parser.parse_args()
     
     if args.command is None:
diff --git a/paimon-python/pypaimon/cli/cli_catalog.py b/paimon-python/pypaimon/cli/cli_catalog.py
new file mode 100644
index 0000000000..072c2b5689
--- /dev/null
+++ b/paimon-python/pypaimon/cli/cli_catalog.py
@@ -0,0 +1,65 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+"""
+Catalog commands for Paimon CLI.
+
+This module provides catalog-related commands for the CLI.
+"""
+
+import sys
+
+
+def cmd_catalog_list_dbs(args):
+    """
+    Execute the 'catalog list-dbs' command.
+
+    Lists all databases in the catalog.
+
+    Args:
+        args: Parsed command line arguments.
+    """
+    from pypaimon.cli.cli import load_catalog_config, create_catalog
+
+    config = load_catalog_config(args.config)
+    catalog = create_catalog(config)
+
+    try:
+        databases = catalog.list_databases()
+    except Exception as e:
+        print(f"Error: Failed to list databases: {e}", file=sys.stderr)
+        sys.exit(1)
+
+    if not databases:
+        print("No databases found.")
+    else:
+        for database_name in databases:
+            print(database_name)
+
+
+def add_catalog_subcommands(catalog_parser):
+    """
+    Add catalog subcommands to the parser.
+
+    Args:
+        catalog_parser: The catalog subparser to add commands to.
+    """
+    catalog_subparsers = catalog_parser.add_subparsers(dest='catalog_command', help='Catalog commands')
+
+    # catalog list-dbs command
+    list_dbs_parser = catalog_subparsers.add_parser('list-dbs', help='List all databases')
+    list_dbs_parser.set_defaults(func=cmd_catalog_list_dbs)
diff --git a/paimon-python/pypaimon/tests/cli_db_test.py b/paimon-python/pypaimon/tests/cli_db_test.py
index 701c622ed2..435368da40 100644
--- a/paimon-python/pypaimon/tests/cli_db_test.py
+++ b/paimon-python/pypaimon/tests/cli_db_test.py
@@ -300,6 +300,39 @@ class CliDbTest(unittest.TestCase):
                 error_output = mock_stderr.getvalue()
                 self.assertIn('Invalid JSON', error_output)
 
+    def test_cli_catalog_list_dbs_basic(self):
+        """Test basic list databases via catalog CLI."""
+        self.catalog.create_database('list_db_a', True)
+        self.catalog.create_database('list_db_b', True)
+
+        with patch('sys.argv',
+                   ['paimon', '-c', self.config_file, 'catalog', 'list-dbs']):
+            with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
+                try:
+                    main()
+                except SystemExit:
+                    pass
+
+                output = mock_stdout.getvalue()
+                self.assertIn('list_db_a', output)
+                self.assertIn('list_db_b', output)
+
+    def test_cli_catalog_list_dbs_excludes_nonexistent(self):
+        """Test list databases does not include non-existent databases."""
+        self.catalog.create_database('list_exists_db', True)
+
+        with patch('sys.argv',
+                   ['paimon', '-c', self.config_file, 'catalog', 'list-dbs']):
+            with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
+                try:
+                    main()
+                except SystemExit:
+                    pass
+
+                output = mock_stdout.getvalue()
+                self.assertIn('list_exists_db', output)
+                self.assertNotIn('never_created_db', output)
+
 
 if __name__ == '__main__':
     unittest.main()