Skip to content

Commit 470da57

Browse files
committed
[python] Introduce db List in Python CLI
1 parent bafbfd6 commit 470da57

File tree

5 files changed

+93
-0
lines changed

5 files changed

+93
-0
lines changed

docs/content/pypaimon/cli.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,21 @@ paimon db alter mydb --remove key1 key2
431431
paimon db alter mydb --set '{"key1": "new_value"}' --remove key2
432432
```
433433

434+
### DB List
435+
436+
List all databases in the catalog.
437+
438+
```shell
439+
paimon db list
440+
```
441+
442+
Output:
443+
```
444+
default
445+
mydb
446+
analytics
447+
```
448+
434449
### DB List Tables
435450

436451
List all tables in a database.

paimon-python/pypaimon/catalog/catalog.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ class Catalog(ABC):
3939
COMMENT_PROP = "comment"
4040
OWNER_PROP = "owner"
4141

42+
@abstractmethod
43+
def list_databases(self) -> List[str]:
44+
"""List all database names in the catalog."""
45+
4246
@abstractmethod
4347
def get_database(self, name: str) -> 'Database':
4448
"""Get paimon database identified by the given name."""

paimon-python/pypaimon/catalog/filesystem_catalog.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ def __init__(self, catalog_options: Options):
4848
self.catalog_options = catalog_options
4949
self.file_io = FileIO.get(self.warehouse, self.catalog_options)
5050

51+
def list_databases(self) -> list:
52+
statuses = self.file_io.list_status(self.warehouse)
53+
database_names = []
54+
for status in statuses:
55+
import pyarrow.fs as pafs
56+
is_directory = hasattr(status, 'type') and status.type == pafs.FileType.Directory
57+
name = status.base_name if hasattr(status, 'base_name') else ""
58+
if is_directory and name and name.endswith(Catalog.DB_SUFFIX):
59+
database_names.append(name[:-len(Catalog.DB_SUFFIX)])
60+
return sorted(database_names)
61+
5162
def get_database(self, name: str) -> Database:
5263
if self.file_io.exists(self.get_database_path(name)):
5364
return Database(name, {})

paimon-python/pypaimon/cli/cli_db.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,32 @@ def cmd_db_alter(args):
169169
sys.exit(1)
170170

171171

172+
def cmd_db_list(args):
173+
"""
174+
Execute the 'db list' command.
175+
176+
Lists all databases in the catalog.
177+
178+
Args:
179+
args: Parsed command line arguments.
180+
"""
181+
from pypaimon.cli.cli import load_catalog_config, create_catalog
182+
183+
config = load_catalog_config(args.config)
184+
catalog = create_catalog(config)
185+
186+
try:
187+
databases = catalog.list_databases()
188+
except Exception as e:
189+
print(f"Error: Failed to list databases: {e}", file=sys.stderr)
190+
sys.exit(1)
191+
192+
if not databases:
193+
print("No databases found.")
194+
else:
195+
for database_name in databases:
196+
print(database_name)
197+
172198
def cmd_db_list_tables(args):
173199
"""
174200
Execute the 'db list-tables' command.
@@ -270,6 +296,10 @@ def add_db_subcommands(db_parser):
270296
)
271297
alter_parser.set_defaults(func=cmd_db_alter)
272298

299+
# db list command
300+
list_parser = db_subparsers.add_parser('list', help='List all databases')
301+
list_parser.set_defaults(func=cmd_db_list)
302+
273303
# db list-tables command
274304
list_tables_parser = db_subparsers.add_parser('list-tables', help='List all tables in a database')
275305
list_tables_parser.add_argument(

paimon-python/pypaimon/tests/cli_db_test.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,39 @@ def test_cli_db_alter_invalid_json(self):
300300
error_output = mock_stderr.getvalue()
301301
self.assertIn('Invalid JSON', error_output)
302302

303+
def test_cli_db_list_basic(self):
304+
"""Test basic list databases via CLI."""
305+
self.catalog.create_database('list_db_a', True)
306+
self.catalog.create_database('list_db_b', True)
307+
308+
with patch('sys.argv',
309+
['paimon', '-c', self.config_file, 'db', 'list']):
310+
with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
311+
try:
312+
main()
313+
except SystemExit:
314+
pass
315+
316+
output = mock_stdout.getvalue()
317+
self.assertIn('list_db_a', output)
318+
self.assertIn('list_db_b', output)
319+
320+
def test_cli_db_list_excludes_nonexistent(self):
321+
"""Test list databases does not include non-existent databases."""
322+
self.catalog.create_database('list_exists_db', True)
323+
324+
with patch('sys.argv',
325+
['paimon', '-c', self.config_file, 'db', 'list']):
326+
with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
327+
try:
328+
main()
329+
except SystemExit:
330+
pass
331+
332+
output = mock_stdout.getvalue()
333+
self.assertIn('list_exists_db', output)
334+
self.assertNotIn('never_created_db', output)
335+
303336

304337
if __name__ == '__main__':
305338
unittest.main()

0 commit comments

Comments
 (0)