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 c913b9ed5a [Python] Reformat code for init_py file (#6159)
c913b9ed5a is described below

commit c913b9ed5afa5341b3fda164572369fca6d656c5
Author: ChengHui Chen <27797326+chenghuic...@users.noreply.github.com>
AuthorDate: Wed Aug 27 15:22:53 2025 +0800

    [Python] Reformat code for init_py file (#6159)
---
 paimon-python/pypaimon/api/__init__.py             | 363 ---------------------
 paimon-python/pypaimon/api/api_request.py          |   6 +-
 paimon-python/pypaimon/api/api_response.py         |  10 +-
 paimon-python/pypaimon/api/auth.py                 |   6 +-
 paimon-python/pypaimon/api/client.py               | 115 +------
 paimon-python/pypaimon/api/resource_paths.py       |  70 ++++
 .../pypaimon/api/{__init__.py => rest_api.py}      | 101 +-----
 paimon-python/pypaimon/api/rest_exception.py       | 111 +++++++
 paimon-python/pypaimon/api/rest_util.py            |  43 +++
 paimon-python/pypaimon/api/token_loader.py         |   5 +-
 paimon-python/pypaimon/catalog/catalog.py          |   2 +-
 .../{table => catalog}/catalog_environment.py      |   7 +-
 paimon-python/pypaimon/catalog/catalog_factory.py  |   1 +
 .../pypaimon/catalog/filesystem_catalog.py         |   4 +-
 .../pypaimon/catalog/{ => rest}/property_change.py |   0
 .../pypaimon/catalog/rest/rest_catalog.py          |  45 +--
 .../pypaimon/catalog/rest/rest_token_file_io.py    |   2 +-
 .../pypaimon/catalog/{ => rest}/table_metadata.py  |   0
 paimon-python/pypaimon/common/identifier.py        |   2 +-
 .../pypaimon/common/{rest_json.py => json_util.py} |   0
 paimon-python/pypaimon/pvfs/__init__.py            |   6 +-
 paimon-python/pypaimon/schema/schema.py            |   2 +-
 paimon-python/pypaimon/schema/schema_manager.py    |   2 +-
 paimon-python/pypaimon/schema/table_schema.py      |   2 +-
 .../catalog_snapshot_commit.py                     |   3 +-
 .../renaming_snapshot_commit.py                    |   5 +-
 paimon-python/pypaimon/snapshot/snapshot.py        |   2 +-
 .../{catalog => snapshot}/snapshot_commit.py       |   4 +-
 .../pypaimon/snapshot/snapshot_manager.py          |   2 +-
 paimon-python/pypaimon/table/file_store_table.py   |   2 +-
 paimon-python/pypaimon/tests/api_test.py           |  35 +-
 paimon-python/pypaimon/tests/predicates_test.py    |   2 +-
 paimon-python/pypaimon/tests/pvfs_test.py          |   4 +-
 .../pypaimon/tests/reader_append_only_test.py      |   2 +-
 .../pypaimon/tests/reader_primary_key_test.py      |   2 +-
 .../pypaimon/tests/rest_catalog_base_test.py       |   5 +-
 paimon-python/pypaimon/tests/rest_server.py        |  42 +--
 .../pypaimon/tests/test_file_store_commit.py       |   2 +-
 .../tests/test_rest_catalog_commit_snapshot.py     |  10 +-
 paimon-python/pypaimon/write/commit_message.py     |   1 +
 paimon-python/pypaimon/write/file_store_commit.py  |   3 +-
 paimon-python/pypaimon/write/row_key_extractor.py  |   1 +
 42 files changed, 364 insertions(+), 668 deletions(-)

diff --git a/paimon-python/pypaimon/api/__init__.py 
b/paimon-python/pypaimon/api/__init__.py
index a384c3f123..a67d5ea255 100644
--- a/paimon-python/pypaimon/api/__init__.py
+++ b/paimon-python/pypaimon/api/__init__.py
@@ -14,366 +14,3 @@
 #  KIND, either express or implied.  See the License for the
 #  specific language governing permissions and limitations
 #  under the License.
-
-import logging
-from typing import Callable, Dict, List, Optional
-from urllib.parse import unquote
-
-from pypaimon.api.api_response import (CommitTableResponse, ConfigResponse,
-                                       GetDatabaseResponse, GetTableResponse,
-                                       GetTableTokenResponse,
-                                       ListDatabasesResponse,
-                                       ListTablesResponse, PagedList,
-                                       PagedResponse)
-from pypaimon.api.api_request import (AlterDatabaseRequest,
-                                      CommitTableRequest,
-                                      CreateDatabaseRequest,
-                                      CreateTableRequest, RenameTableRequest)
-from pypaimon.api.auth import AuthProviderFactory, RESTAuthFunction
-from pypaimon.api.client import HttpClient
-from pypaimon.api.typedef import T
-from pypaimon.catalog.snapshot_commit import PartitionStatistics
-from pypaimon.common.config import CatalogOptions
-from pypaimon.common.identifier import Identifier
-from pypaimon.schema.schema import Schema
-from pypaimon.snapshot.snapshot import Snapshot
-
-
-class RESTException(Exception):
-    pass
-
-
-class AlreadyExistsException(RESTException):
-    pass
-
-
-class ForbiddenException(RESTException):
-    pass
-
-
-class NoSuchResourceException(RESTException):
-    pass
-
-
-class RESTUtil:
-    @staticmethod
-    def encode_string(value: str) -> str:
-        import urllib.parse
-
-        return urllib.parse.quote(value)
-
-    @staticmethod
-    def decode_string(encoded: str) -> str:
-        """Decode URL-encoded string"""
-        return unquote(encoded)
-
-    @staticmethod
-    def extract_prefix_map(
-            options: Dict[str, str], prefix: str) -> Dict[str, str]:
-        result = {}
-        config = options
-        for key, value in config.items():
-            if key.startswith(prefix):
-                new_key = key[len(prefix):]
-                result[new_key] = str(value)
-        return result
-
-
-class ResourcePaths:
-    V1 = "v1"
-    DATABASES = "databases"
-    TABLES = "tables"
-    TABLE_DETAILS = "table-details"
-
-    def __init__(self, prefix: str):
-        self.base_path = f"/{self.V1}/{prefix}".rstrip("/")
-
-    @classmethod
-    def for_catalog_properties(
-            cls, options: dict[str, str]) -> "ResourcePaths":
-        prefix = options.get(CatalogOptions.PREFIX, "")
-        return cls(prefix)
-
-    @staticmethod
-    def config() -> str:
-        return f"/{ResourcePaths.V1}/config"
-
-    def databases(self) -> str:
-        return f"{self.base_path}/{self.DATABASES}"
-
-    def database(self, name: str) -> str:
-        return 
f"{self.base_path}/{self.DATABASES}/{RESTUtil.encode_string(name)}"
-
-    def tables(self, database_name: Optional[str] = None) -> str:
-        if database_name:
-            return 
f"{self.base_path}/{self.DATABASES}/{RESTUtil.encode_string(database_name)}/{self.TABLES}"
-        return f"{self.base_path}/{self.TABLES}"
-
-    def table(self, database_name: str, table_name: str) -> str:
-        return 
(f"{self.base_path}/{self.DATABASES}/{RESTUtil.encode_string(database_name)}"
-                f"/{self.TABLES}/{RESTUtil.encode_string(table_name)}")
-
-    def table_details(self, database_name: str) -> str:
-        return 
f"{self.base_path}/{self.DATABASES}/{database_name}/{self.TABLE_DETAILS}"
-
-    def table_token(self, database_name: str, table_name: str) -> str:
-        return 
(f"{self.base_path}/{self.DATABASES}/{RESTUtil.encode_string(database_name)}"
-                f"/{self.TABLES}/{RESTUtil.encode_string(table_name)}/token")
-
-    def rename_table(self) -> str:
-        return f"{self.base_path}/{self.TABLES}/rename"
-
-    def commit_table(self, database_name: str, table_name: str) -> str:
-        return 
(f"{self.base_path}/{self.DATABASES}/{RESTUtil.encode_string(database_name)}"
-                f"/{self.TABLES}/{RESTUtil.encode_string(table_name)}/commit")
-
-
-class RESTApi:
-    HEADER_PREFIX = "header."
-    MAX_RESULTS = "maxResults"
-    PAGE_TOKEN = "pageToken"
-    DATABASE_NAME_PATTERN = "databaseNamePattern"
-    TABLE_NAME_PATTERN = "tableNamePattern"
-    TOKEN_EXPIRATION_SAFE_TIME_MILLIS = 3_600_000
-
-    def __init__(self, options: Dict[str, str], config_required: bool = True):
-        self.logger = logging.getLogger(self.__class__.__name__)
-        self.client = HttpClient(options.get(CatalogOptions.URI))
-        auth_provider = AuthProviderFactory.create_auth_provider(options)
-        base_headers = RESTUtil.extract_prefix_map(options, self.HEADER_PREFIX)
-
-        if config_required:
-            warehouse = options.get(CatalogOptions.WAREHOUSE)
-            query_params = {}
-            if warehouse:
-                query_params[CatalogOptions.WAREHOUSE] = 
RESTUtil.encode_string(
-                    warehouse)
-
-            config_response = self.client.get_with_params(
-                ResourcePaths.config(),
-                query_params,
-                ConfigResponse,
-                RESTAuthFunction(base_headers, auth_provider),
-            )
-            options = config_response.merge(options)
-            base_headers.update(
-                RESTUtil.extract_prefix_map(options, self.HEADER_PREFIX)
-            )
-
-        self.rest_auth_function = RESTAuthFunction(base_headers, auth_provider)
-        self.options = options
-        self.resource_paths = ResourcePaths.for_catalog_properties(options)
-
-    def __build_paged_query_params(
-            max_results: Optional[int],
-            page_token: Optional[str],
-            name_patterns: Dict[str, str],
-    ) -> Dict[str, str]:
-        query_params = {}
-        if max_results is not None and max_results > 0:
-            query_params[RESTApi.MAX_RESULTS] = str(max_results)
-
-        if page_token is not None and page_token.strip():
-            query_params[RESTApi.PAGE_TOKEN] = page_token
-
-        for key, value in name_patterns:
-            if key and value and key.strip() and value.strip():
-                query_params[key] = value
-
-        return query_params
-
-    def __list_data_from_page_api(
-            self, page_api: Callable[[Dict[str, str]], PagedResponse[T]]
-    ) -> List[T]:
-        results = []
-        query_params = {}
-        page_token = None
-
-        while True:
-            if page_token:
-                query_params[RESTApi.PAGE_TOKEN] = page_token
-            elif RESTApi.PAGE_TOKEN in query_params:
-                del query_params[RESTApi.PAGE_TOKEN]
-
-            response = page_api(query_params)
-
-            if response.data:
-                results.extend(response.data())
-
-            page_token = response.next_page_token
-
-            if not page_token or not response.data:
-                break
-
-        return results
-
-    def get_options(self) -> dict[str, str]:
-        return self.options
-
-    def list_databases(self) -> List[str]:
-        return self.__list_data_from_page_api(
-            lambda query_params: self.client.get_with_params(
-                self.resource_paths.databases(),
-                query_params,
-                ListDatabasesResponse,
-                self.rest_auth_function,
-            )
-        )
-
-    def list_databases_paged(
-            self,
-            max_results: Optional[int] = None,
-            page_token: Optional[str] = None,
-            database_name_pattern: Optional[str] = None,
-    ) -> PagedList[str]:
-
-        response = self.client.get_with_params(
-            self.resource_paths.databases(),
-            self.__build_paged_query_params(
-                max_results,
-                page_token,
-                {self.DATABASE_NAME_PATTERN: database_name_pattern},
-            ),
-            ListDatabasesResponse,
-            self.rest_auth_function,
-        )
-
-        databases = response.data() or []
-        return PagedList(databases, response.get_next_page_token())
-
-    def create_database(self, name: str, options: Dict[str, str]) -> None:
-        request = CreateDatabaseRequest(name, options)
-        self.client.post(
-            self.resource_paths.databases(), request, self.rest_auth_function
-        )
-
-    def get_database(self, name: str) -> GetDatabaseResponse:
-        return self.client.get(
-            self.resource_paths.database(name),
-            GetDatabaseResponse,
-            self.rest_auth_function,
-        )
-
-    def drop_database(self, name: str) -> None:
-        self.client.delete(
-            self.resource_paths.database(name),
-            self.rest_auth_function)
-
-    def alter_database(
-            self,
-            name: str,
-            removals: Optional[List[str]] = None,
-            updates: Optional[Dict[str, str]] = None,
-    ):
-        if not name or not name.strip():
-            raise ValueError("Database name cannot be empty")
-        removals = removals or []
-        updates = updates or {}
-        request = AlterDatabaseRequest(removals, updates)
-
-        return self.client.post(
-            self.resource_paths.database(name),
-            request,
-            self.rest_auth_function)
-
-    def list_tables(self, database_name: str) -> List[str]:
-        return self.__list_data_from_page_api(
-            lambda query_params: self.client.get_with_params(
-                self.resource_paths.tables(database_name),
-                query_params,
-                ListTablesResponse,
-                self.rest_auth_function,
-            )
-        )
-
-    def list_tables_paged(
-            self,
-            database_name: str,
-            max_results: Optional[int] = None,
-            page_token: Optional[str] = None,
-            table_name_pattern: Optional[str] = None,
-    ) -> PagedList[str]:
-        response = self.client.get_with_params(
-            self.resource_paths.tables(database_name),
-            self.__build_paged_query_params(
-                max_results, page_token, {self.TABLE_NAME_PATTERN: 
table_name_pattern}
-            ),
-            ListTablesResponse,
-            self.rest_auth_function,
-        )
-
-        tables = response.data() or []
-        return PagedList(tables, response.get_next_page_token())
-
-    def create_table(self, identifier: Identifier, schema: Schema) -> None:
-        request = CreateTableRequest(identifier, schema)
-        return self.client.post(
-            self.resource_paths.tables(identifier.database_name),
-            request,
-            self.rest_auth_function)
-
-    def get_table(self, identifier: Identifier) -> GetTableResponse:
-        return self.client.get(
-            self.resource_paths.table(
-                identifier.database_name,
-                identifier.object_name),
-            GetTableResponse,
-            self.rest_auth_function,
-        )
-
-    def drop_table(self, identifier: Identifier) -> GetTableResponse:
-        return self.client.delete(
-            self.resource_paths.table(
-                identifier.database_name,
-                identifier.object_name),
-            self.rest_auth_function,
-        )
-
-    def rename_table(self, source_identifier: Identifier, target_identifier: 
Identifier) -> None:
-        request = RenameTableRequest(source_identifier, target_identifier)
-        return self.client.post(
-            self.resource_paths.rename_table(),
-            request,
-            self.rest_auth_function)
-
-    def load_table_token(self, identifier: Identifier) -> 
GetTableTokenResponse:
-        return self.client.get(
-            self.resource_paths.table_token(
-                identifier.database_name,
-                identifier.object_name),
-            GetTableTokenResponse,
-            self.rest_auth_function,
-        )
-
-    def commit_snapshot(
-            self,
-            identifier: Identifier,
-            table_uuid: Optional[str],
-            snapshot: Snapshot,
-            statistics: List[PartitionStatistics]
-    ) -> bool:
-        """
-        Commit snapshot for table.
-
-        Args:
-            identifier: Database name and table name
-            table_uuid: UUID of the table to avoid wrong commit
-            snapshot: Snapshot for committing
-            statistics: Statistics for this snapshot incremental
-
-        Returns:
-            True if commit success
-
-        Raises:
-            NoSuchResourceException: Exception thrown on HTTP 404 means the 
table not exists
-            ForbiddenException: Exception thrown on HTTP 403 means don't have 
the permission for this table
-        """
-        request = CommitTableRequest(table_uuid, snapshot, statistics)
-        response = self.client.post_with_response_type(
-            self.resource_paths.commit_table(
-                identifier.database_name, identifier.object_name),
-            request,
-            CommitTableResponse,
-            self.rest_auth_function
-        )
-        return response.is_success()
diff --git a/paimon-python/pypaimon/api/api_request.py 
b/paimon-python/pypaimon/api/api_request.py
index cf22d9853b..d453250757 100644
--- a/paimon-python/pypaimon/api/api_request.py
+++ b/paimon-python/pypaimon/api/api_request.py
@@ -20,15 +20,15 @@ from abc import ABC
 from dataclasses import dataclass
 from typing import Dict, List, Optional
 
-from pypaimon.catalog.snapshot_commit import PartitionStatistics
 from pypaimon.common.identifier import Identifier
-from pypaimon.common.rest_json import json_field
+from pypaimon.common.json_util import json_field
 from pypaimon.schema.schema import Schema
 from pypaimon.snapshot.snapshot import Snapshot
+from pypaimon.snapshot.snapshot_commit import PartitionStatistics
 
 
 class RESTRequest(ABC):
-    pass
+    """RESTRequest"""
 
 
 @dataclass
diff --git a/paimon-python/pypaimon/api/api_response.py 
b/paimon-python/pypaimon/api/api_response.py
index 5658f5b351..0cc82f31b5 100644
--- a/paimon-python/pypaimon/api/api_response.py
+++ b/paimon-python/pypaimon/api/api_response.py
@@ -20,11 +20,9 @@ from abc import ABC, abstractmethod
 from dataclasses import dataclass
 from typing import Dict, Generic, List, Optional
 
-from pypaimon.common.rest_json import json_field
+from pypaimon.common.json_util import T, json_field
 from pypaimon.schema.schema import Schema
 
-from .typedef import T
-
 
 @dataclass
 class PagedList(Generic[T]):
@@ -33,7 +31,7 @@ class PagedList(Generic[T]):
 
 
 class RESTResponse(ABC):
-    pass
+    """RESTResponse"""
 
 
 @dataclass
@@ -99,11 +97,11 @@ class PagedResponse(RESTResponse, Generic[T]):
 
     @abstractmethod
     def data(self) -> List[T]:
-        pass
+        """data"""
 
     @abstractmethod
     def get_next_page_token(self) -> str:
-        pass
+        """get_next_page_token"""
 
 
 @dataclass
diff --git a/paimon-python/pypaimon/api/auth.py 
b/paimon-python/pypaimon/api/auth.py
index de20d96c8e..a0d62e2860 100644
--- a/paimon-python/pypaimon/api/auth.py
+++ b/paimon-python/pypaimon/api/auth.py
@@ -25,11 +25,11 @@ from collections import OrderedDict
 from datetime import datetime, timezone
 from typing import Dict, Optional
 
+from pypaimon.api.token_loader import (DLFToken, DLFTokenLoader,
+                                       DLFTokenLoaderFactory)
+from pypaimon.api.typedef import RESTAuthParameter
 from pypaimon.common.config import CatalogOptions
 
-from .token_loader import DLFToken, DLFTokenLoader, DLFTokenLoaderFactory
-from .typedef import RESTAuthParameter
-
 
 class AuthProvider(ABC):
 
diff --git a/paimon-python/pypaimon/api/client.py 
b/paimon-python/pypaimon/api/client.py
index e7e42abe7a..9e30df598b 100644
--- a/paimon-python/pypaimon/api/client.py
+++ b/paimon-python/pypaimon/api/client.py
@@ -19,124 +19,39 @@ limitations under the License.
 import json
 import logging
 import time
-import traceback
 import urllib.parse
 from abc import ABC, abstractmethod
-from typing import Any, Callable, Dict, Optional, Type, TypeVar
+from typing import Callable, Dict, Optional, Type, TypeVar
 
 import requests
 from requests.adapters import HTTPAdapter
 from urllib3 import Retry
 
-from pypaimon.common.rest_json import JSON
-
-from .api_response import ErrorResponse
-from .typedef import RESTAuthParameter
+from pypaimon.api.api_response import ErrorResponse
+from pypaimon.api.rest_exception import (AlreadyExistsException,
+                                         BadRequestException,
+                                         ForbiddenException,
+                                         NoSuchResourceException,
+                                         NotAuthorizedException,
+                                         NotImplementedException,
+                                         RESTException,
+                                         ServiceFailureException,
+                                         ServiceUnavailableException)
+from pypaimon.api.typedef import RESTAuthParameter
+from pypaimon.common.json_util import JSON
 
 T = TypeVar('T', bound='RESTResponse')
 
 
 class RESTRequest(ABC):
-    pass
-
-
-class RESTException(Exception):
-    def __init__(self, message: str = None, *args: Any, cause: 
Optional[Exception] = None):
-        if message and args:
-            try:
-                formatted_message = message % args
-            except (TypeError, ValueError):
-                formatted_message = f"{message} {' '.join(str(arg) for arg in 
args)}"
-        else:
-            formatted_message = message or "REST API error occurred"
-
-        super().__init__(formatted_message)
-        self.__cause__ = cause
-
-    def get_cause(self) -> Optional[Exception]:
-        return self.__cause__
-
-    def get_message(self) -> str:
-        return str(self)
-
-    def print_stack_trace(self) -> None:
-        traceback.print_exception(type(self), self, self.__traceback__)
-
-    def get_stack_trace(self) -> str:
-        return ''.join(traceback.format_exception(type(self), self, 
self.__traceback__))
-
-    def __repr__(self) -> str:
-        if self.__cause__:
-            return f"{self.__class__.__name__}('{self}', caused by 
{type(self.__cause__).__name__}: {self.__cause__})"
-        return f"{self.__class__.__name__}('{self}')"
-
-
-class BadRequestException(RESTException):
-
-    def __init__(self, message: str = None, *args: Any):
-        super().__init__(message, *args)
-
-
-class NotAuthorizedException(RESTException):
-    """Exception for not authorized (401)"""
-
-    def __init__(self, message: str, *args: Any):
-        super().__init__(message, *args)
-
-
-class ForbiddenException(RESTException):
-    """Exception for forbidden access (403)"""
-
-    def __init__(self, message: str, *args: Any):
-        super().__init__(message, *args)
-
-
-class NoSuchResourceException(RESTException):
-    """Exception for resource not found (404)"""
-
-    def __init__(self, resource_type: Optional[str], resource_name: 
Optional[str],
-                 message: str, *args: Any):
-        self.resource_type = resource_type
-        self.resource_name = resource_name
-        super().__init__(message, *args)
-
-
-class AlreadyExistsException(RESTException):
-    """Exception for resource already exists (409)"""
-
-    def __init__(self, resource_type: Optional[str], resource_name: 
Optional[str],
-                 message: str, *args: Any):
-        self.resource_type = resource_type
-        self.resource_name = resource_name
-        super().__init__(message, *args)
-
-
-class ServiceFailureException(RESTException):
-    """Exception for service failure (500)"""
-
-    def __init__(self, message: str, *args: Any):
-        super().__init__(message, *args)
-
-
-class NotImplementedException(RESTException):
-    """Exception for not implemented (501)"""
-
-    def __init__(self, message: str, *args: Any):
-        super().__init__(message, *args)
-
-
-class ServiceUnavailableException(RESTException):
-    """Exception for service unavailable (503)"""
-
-    def __init__(self, message: str, *args: Any):
-        super().__init__(message, *args)
+    """RESTRequest"""
 
 
 class ErrorHandler(ABC):
 
     @abstractmethod
     def accept(self, error: ErrorResponse, request_id: str) -> None:
-        pass
+        """accept"""
 
 
 # DefaultErrorHandler implementation
diff --git a/paimon-python/pypaimon/api/resource_paths.py 
b/paimon-python/pypaimon/api/resource_paths.py
new file mode 100644
index 0000000000..0214ab0529
--- /dev/null
+++ b/paimon-python/pypaimon/api/resource_paths.py
@@ -0,0 +1,70 @@
+#  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.
+
+from typing import Optional
+
+from pypaimon.api.rest_util import RESTUtil
+from pypaimon.common.config import CatalogOptions
+
+
+class ResourcePaths:
+    V1 = "v1"
+    DATABASES = "databases"
+    TABLES = "tables"
+    TABLE_DETAILS = "table-details"
+
+    def __init__(self, prefix: str):
+        self.base_path = f"/{self.V1}/{prefix}".rstrip("/")
+
+    @classmethod
+    def for_catalog_properties(
+            cls, options: dict[str, str]) -> "ResourcePaths":
+        prefix = options.get(CatalogOptions.PREFIX, "")
+        return cls(prefix)
+
+    @staticmethod
+    def config() -> str:
+        return f"/{ResourcePaths.V1}/config"
+
+    def databases(self) -> str:
+        return f"{self.base_path}/{self.DATABASES}"
+
+    def database(self, name: str) -> str:
+        return 
f"{self.base_path}/{self.DATABASES}/{RESTUtil.encode_string(name)}"
+
+    def tables(self, database_name: Optional[str] = None) -> str:
+        if database_name:
+            return 
f"{self.base_path}/{self.DATABASES}/{RESTUtil.encode_string(database_name)}/{self.TABLES}"
+        return f"{self.base_path}/{self.TABLES}"
+
+    def table(self, database_name: str, table_name: str) -> str:
+        return 
(f"{self.base_path}/{self.DATABASES}/{RESTUtil.encode_string(database_name)}"
+                f"/{self.TABLES}/{RESTUtil.encode_string(table_name)}")
+
+    def table_details(self, database_name: str) -> str:
+        return 
f"{self.base_path}/{self.DATABASES}/{database_name}/{self.TABLE_DETAILS}"
+
+    def table_token(self, database_name: str, table_name: str) -> str:
+        return 
(f"{self.base_path}/{self.DATABASES}/{RESTUtil.encode_string(database_name)}"
+                f"/{self.TABLES}/{RESTUtil.encode_string(table_name)}/token")
+
+    def rename_table(self) -> str:
+        return f"{self.base_path}/{self.TABLES}/rename"
+
+    def commit_table(self, database_name: str, table_name: str) -> str:
+        return 
(f"{self.base_path}/{self.DATABASES}/{RESTUtil.encode_string(database_name)}"
+                f"/{self.TABLES}/{RESTUtil.encode_string(table_name)}/commit")
diff --git a/paimon-python/pypaimon/api/__init__.py 
b/paimon-python/pypaimon/api/rest_api.py
similarity index 77%
copy from paimon-python/pypaimon/api/__init__.py
copy to paimon-python/pypaimon/api/rest_api.py
index a384c3f123..2e341733bd 100644
--- a/paimon-python/pypaimon/api/__init__.py
+++ b/paimon-python/pypaimon/api/rest_api.py
@@ -17,115 +17,26 @@
 
 import logging
 from typing import Callable, Dict, List, Optional
-from urllib.parse import unquote
 
+from pypaimon.api.api_request import (AlterDatabaseRequest, CommitTableRequest,
+                                      CreateDatabaseRequest,
+                                      CreateTableRequest, RenameTableRequest)
 from pypaimon.api.api_response import (CommitTableResponse, ConfigResponse,
                                        GetDatabaseResponse, GetTableResponse,
                                        GetTableTokenResponse,
                                        ListDatabasesResponse,
                                        ListTablesResponse, PagedList,
                                        PagedResponse)
-from pypaimon.api.api_request import (AlterDatabaseRequest,
-                                      CommitTableRequest,
-                                      CreateDatabaseRequest,
-                                      CreateTableRequest, RenameTableRequest)
 from pypaimon.api.auth import AuthProviderFactory, RESTAuthFunction
 from pypaimon.api.client import HttpClient
+from pypaimon.api.resource_paths import ResourcePaths
+from pypaimon.api.rest_util import RESTUtil
 from pypaimon.api.typedef import T
-from pypaimon.catalog.snapshot_commit import PartitionStatistics
 from pypaimon.common.config import CatalogOptions
 from pypaimon.common.identifier import Identifier
 from pypaimon.schema.schema import Schema
 from pypaimon.snapshot.snapshot import Snapshot
-
-
-class RESTException(Exception):
-    pass
-
-
-class AlreadyExistsException(RESTException):
-    pass
-
-
-class ForbiddenException(RESTException):
-    pass
-
-
-class NoSuchResourceException(RESTException):
-    pass
-
-
-class RESTUtil:
-    @staticmethod
-    def encode_string(value: str) -> str:
-        import urllib.parse
-
-        return urllib.parse.quote(value)
-
-    @staticmethod
-    def decode_string(encoded: str) -> str:
-        """Decode URL-encoded string"""
-        return unquote(encoded)
-
-    @staticmethod
-    def extract_prefix_map(
-            options: Dict[str, str], prefix: str) -> Dict[str, str]:
-        result = {}
-        config = options
-        for key, value in config.items():
-            if key.startswith(prefix):
-                new_key = key[len(prefix):]
-                result[new_key] = str(value)
-        return result
-
-
-class ResourcePaths:
-    V1 = "v1"
-    DATABASES = "databases"
-    TABLES = "tables"
-    TABLE_DETAILS = "table-details"
-
-    def __init__(self, prefix: str):
-        self.base_path = f"/{self.V1}/{prefix}".rstrip("/")
-
-    @classmethod
-    def for_catalog_properties(
-            cls, options: dict[str, str]) -> "ResourcePaths":
-        prefix = options.get(CatalogOptions.PREFIX, "")
-        return cls(prefix)
-
-    @staticmethod
-    def config() -> str:
-        return f"/{ResourcePaths.V1}/config"
-
-    def databases(self) -> str:
-        return f"{self.base_path}/{self.DATABASES}"
-
-    def database(self, name: str) -> str:
-        return 
f"{self.base_path}/{self.DATABASES}/{RESTUtil.encode_string(name)}"
-
-    def tables(self, database_name: Optional[str] = None) -> str:
-        if database_name:
-            return 
f"{self.base_path}/{self.DATABASES}/{RESTUtil.encode_string(database_name)}/{self.TABLES}"
-        return f"{self.base_path}/{self.TABLES}"
-
-    def table(self, database_name: str, table_name: str) -> str:
-        return 
(f"{self.base_path}/{self.DATABASES}/{RESTUtil.encode_string(database_name)}"
-                f"/{self.TABLES}/{RESTUtil.encode_string(table_name)}")
-
-    def table_details(self, database_name: str) -> str:
-        return 
f"{self.base_path}/{self.DATABASES}/{database_name}/{self.TABLE_DETAILS}"
-
-    def table_token(self, database_name: str, table_name: str) -> str:
-        return 
(f"{self.base_path}/{self.DATABASES}/{RESTUtil.encode_string(database_name)}"
-                f"/{self.TABLES}/{RESTUtil.encode_string(table_name)}/token")
-
-    def rename_table(self) -> str:
-        return f"{self.base_path}/{self.TABLES}/rename"
-
-    def commit_table(self, database_name: str, table_name: str) -> str:
-        return 
(f"{self.base_path}/{self.DATABASES}/{RESTUtil.encode_string(database_name)}"
-                f"/{self.TABLES}/{RESTUtil.encode_string(table_name)}/commit")
+from pypaimon.snapshot.snapshot_commit import PartitionStatistics
 
 
 class RESTApi:
diff --git a/paimon-python/pypaimon/api/rest_exception.py 
b/paimon-python/pypaimon/api/rest_exception.py
new file mode 100644
index 0000000000..738de5efdd
--- /dev/null
+++ b/paimon-python/pypaimon/api/rest_exception.py
@@ -0,0 +1,111 @@
+#  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.
+
+import traceback
+from typing import Any, Optional
+
+
+class RESTException(Exception):
+    def __init__(self, message: str = None, *args: Any, cause: 
Optional[Exception] = None):
+        if message and args:
+            try:
+                formatted_message = message % args
+            except (TypeError, ValueError):
+                formatted_message = f"{message} {' '.join(str(arg) for arg in 
args)}"
+        else:
+            formatted_message = message or "REST API error occurred"
+
+        super().__init__(formatted_message)
+        self.__cause__ = cause
+
+    def get_cause(self) -> Optional[Exception]:
+        return self.__cause__
+
+    def get_message(self) -> str:
+        return str(self)
+
+    def print_stack_trace(self) -> None:
+        traceback.print_exception(type(self), self, self.__traceback__)
+
+    def get_stack_trace(self) -> str:
+        return ''.join(traceback.format_exception(type(self), self, 
self.__traceback__))
+
+    def __repr__(self) -> str:
+        if self.__cause__:
+            return f"{self.__class__.__name__}('{self}', caused by 
{type(self.__cause__).__name__}: {self.__cause__})"
+        return f"{self.__class__.__name__}('{self}')"
+
+
+class BadRequestException(RESTException):
+
+    def __init__(self, message: str = None, *args: Any):
+        super().__init__(message, *args)
+
+
+class NotAuthorizedException(RESTException):
+    """Exception for not authorized (401)"""
+
+    def __init__(self, message: str, *args: Any):
+        super().__init__(message, *args)
+
+
+class ForbiddenException(RESTException):
+    """Exception for forbidden access (403)"""
+
+    def __init__(self, message: str, *args: Any):
+        super().__init__(message, *args)
+
+
+class NoSuchResourceException(RESTException):
+    """Exception for resource not found (404)"""
+
+    def __init__(self, resource_type: Optional[str], resource_name: 
Optional[str],
+                 message: str, *args: Any):
+        self.resource_type = resource_type
+        self.resource_name = resource_name
+        super().__init__(message, *args)
+
+
+class AlreadyExistsException(RESTException):
+    """Exception for resource already exists (409)"""
+
+    def __init__(self, resource_type: Optional[str], resource_name: 
Optional[str],
+                 message: str, *args: Any):
+        self.resource_type = resource_type
+        self.resource_name = resource_name
+        super().__init__(message, *args)
+
+
+class ServiceFailureException(RESTException):
+    """Exception for service failure (500)"""
+
+    def __init__(self, message: str, *args: Any):
+        super().__init__(message, *args)
+
+
+class NotImplementedException(RESTException):
+    """Exception for not implemented (501)"""
+
+    def __init__(self, message: str, *args: Any):
+        super().__init__(message, *args)
+
+
+class ServiceUnavailableException(RESTException):
+    """Exception for service unavailable (503)"""
+
+    def __init__(self, message: str, *args: Any):
+        super().__init__(message, *args)
diff --git a/paimon-python/pypaimon/api/rest_util.py 
b/paimon-python/pypaimon/api/rest_util.py
new file mode 100644
index 0000000000..6c2dd3c644
--- /dev/null
+++ b/paimon-python/pypaimon/api/rest_util.py
@@ -0,0 +1,43 @@
+#  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.
+
+from typing import Dict
+from urllib.parse import unquote
+
+
+class RESTUtil:
+    @staticmethod
+    def encode_string(value: str) -> str:
+        import urllib.parse
+
+        return urllib.parse.quote(value)
+
+    @staticmethod
+    def decode_string(encoded: str) -> str:
+        """Decode URL-encoded string"""
+        return unquote(encoded)
+
+    @staticmethod
+    def extract_prefix_map(
+            options: Dict[str, str], prefix: str) -> Dict[str, str]:
+        result = {}
+        config = options
+        for key, value in config.items():
+            if key.startswith(prefix):
+                new_key = key[len(prefix):]
+                result[new_key] = str(value)
+        return result
diff --git a/paimon-python/pypaimon/api/token_loader.py 
b/paimon-python/pypaimon/api/token_loader.py
index 0d332c6c1f..8e65846bf8 100644
--- a/paimon-python/pypaimon/api/token_loader.py
+++ b/paimon-python/pypaimon/api/token_loader.py
@@ -25,10 +25,9 @@ import requests
 from requests.adapters import HTTPAdapter
 from requests.exceptions import RequestException
 
+from pypaimon.api.client import ExponentialRetry
 from pypaimon.common.config import CatalogOptions
-from pypaimon.common.rest_json import JSON, json_field
-
-from .client import ExponentialRetry
+from pypaimon.common.json_util import JSON, json_field
 
 
 @dataclass
diff --git a/paimon-python/pypaimon/catalog/catalog.py 
b/paimon-python/pypaimon/catalog/catalog.py
index c2b1f6915e..a8e7dcd065 100644
--- a/paimon-python/pypaimon/catalog/catalog.py
+++ b/paimon-python/pypaimon/catalog/catalog.py
@@ -19,10 +19,10 @@
 from abc import ABC, abstractmethod
 from typing import List, Optional, Union
 
-from pypaimon.catalog.snapshot_commit import PartitionStatistics
 from pypaimon.common.identifier import Identifier
 from pypaimon.schema.schema import Schema
 from pypaimon.snapshot.snapshot import Snapshot
+from pypaimon.snapshot.snapshot_commit import PartitionStatistics
 
 
 class Catalog(ABC):
diff --git a/paimon-python/pypaimon/table/catalog_environment.py 
b/paimon-python/pypaimon/catalog/catalog_environment.py
similarity index 93%
rename from paimon-python/pypaimon/table/catalog_environment.py
rename to paimon-python/pypaimon/catalog/catalog_environment.py
index f025b367b3..762a42dd6a 100644
--- a/paimon-python/pypaimon/table/catalog_environment.py
+++ b/paimon-python/pypaimon/catalog/catalog_environment.py
@@ -15,13 +15,14 @@ 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.
 """
+
 from typing import Optional
 
 from pypaimon.catalog.catalog_loader import CatalogLoader
-from pypaimon.catalog.catalog_snapshot_commit import CatalogSnapshotCommit
-from pypaimon.catalog.renaming_snapshot_commit import RenamingSnapshotCommit
-from pypaimon.catalog.snapshot_commit import SnapshotCommit
 from pypaimon.common.identifier import Identifier
+from pypaimon.snapshot.catalog_snapshot_commit import CatalogSnapshotCommit
+from pypaimon.snapshot.renaming_snapshot_commit import RenamingSnapshotCommit
+from pypaimon.snapshot.snapshot_commit import SnapshotCommit
 
 
 class CatalogEnvironment:
diff --git a/paimon-python/pypaimon/catalog/catalog_factory.py 
b/paimon-python/pypaimon/catalog/catalog_factory.py
index 7bae23be7e..865ffe4766 100644
--- a/paimon-python/pypaimon/catalog/catalog_factory.py
+++ b/paimon-python/pypaimon/catalog/catalog_factory.py
@@ -15,6 +15,7 @@
 #  See the License for the specific language governing permissions and
 # limitations under the License.
 
################################################################################
+
 from pypaimon.api.options import Options
 from pypaimon.catalog.catalog import Catalog
 from pypaimon.catalog.catalog_context import CatalogContext
diff --git a/paimon-python/pypaimon/catalog/filesystem_catalog.py 
b/paimon-python/pypaimon/catalog/filesystem_catalog.py
index 1aed6e8137..8de2850e4a 100644
--- a/paimon-python/pypaimon/catalog/filesystem_catalog.py
+++ b/paimon-python/pypaimon/catalog/filesystem_catalog.py
@@ -21,19 +21,19 @@ from typing import List, Optional, Union
 from urllib.parse import urlparse
 
 from pypaimon.catalog.catalog import Catalog
+from pypaimon.catalog.catalog_environment import CatalogEnvironment
 from pypaimon.catalog.catalog_exception import (DatabaseAlreadyExistException,
                                                 DatabaseNotExistException,
                                                 TableAlreadyExistException,
                                                 TableNotExistException)
 from pypaimon.catalog.database import Database
-from pypaimon.catalog.snapshot_commit import PartitionStatistics
 from pypaimon.common.config import CatalogOptions
 from pypaimon.common.core_options import CoreOptions
 from pypaimon.common.file_io import FileIO
 from pypaimon.common.identifier import Identifier
 from pypaimon.schema.schema_manager import SchemaManager
 from pypaimon.snapshot.snapshot import Snapshot
-from pypaimon.table.catalog_environment import CatalogEnvironment
+from pypaimon.snapshot.snapshot_commit import PartitionStatistics
 from pypaimon.table.file_store_table import FileStoreTable
 from pypaimon.table.table import Table
 
diff --git a/paimon-python/pypaimon/catalog/property_change.py 
b/paimon-python/pypaimon/catalog/rest/property_change.py
similarity index 100%
rename from paimon-python/pypaimon/catalog/property_change.py
rename to paimon-python/pypaimon/catalog/rest/property_change.py
diff --git a/paimon-python/pypaimon/catalog/rest/rest_catalog.py 
b/paimon-python/pypaimon/catalog/rest/rest_catalog.py
index f35ee04322..31cafb2578 100644
--- a/paimon-python/pypaimon/catalog/rest/rest_catalog.py
+++ b/paimon-python/pypaimon/catalog/rest/rest_catalog.py
@@ -19,35 +19,36 @@ from pathlib import Path
 from typing import Any, Callable, Dict, List, Optional, Union
 from urllib.parse import urlparse
 
-from pypaimon.api import (CatalogOptions,
-                          NoSuchResourceException, RESTApi)
 from pypaimon.api.api_response import GetTableResponse, PagedList
 from pypaimon.api.options import Options
+from pypaimon.api.rest_api import RESTApi
+from pypaimon.api.rest_exception import NoSuchResourceException
 from pypaimon.catalog.catalog import Catalog
 from pypaimon.catalog.catalog_context import CatalogContext
+from pypaimon.catalog.catalog_environment import CatalogEnvironment
 from pypaimon.catalog.catalog_exception import TableNotExistException
 from pypaimon.catalog.database import Database
-from pypaimon.catalog.property_change import PropertyChange
+from pypaimon.catalog.rest.property_change import PropertyChange
 from pypaimon.catalog.rest.rest_token_file_io import RESTTokenFileIO
-from pypaimon.catalog.snapshot_commit import PartitionStatistics
-from pypaimon.catalog.table_metadata import TableMetadata
+from pypaimon.catalog.rest.table_metadata import TableMetadata
+from pypaimon.common.config import CatalogOptions
 from pypaimon.common.core_options import CoreOptions
 from pypaimon.common.file_io import FileIO
 from pypaimon.common.identifier import Identifier
 from pypaimon.schema.schema import Schema
 from pypaimon.schema.table_schema import TableSchema
 from pypaimon.snapshot.snapshot import Snapshot
-from pypaimon.table.catalog_environment import CatalogEnvironment
+from pypaimon.snapshot.snapshot_commit import PartitionStatistics
 from pypaimon.table.file_store_table import FileStoreTable
 
 
 class RESTCatalog(Catalog):
     def __init__(self, context: CatalogContext, config_required: 
Optional[bool] = True):
         self.warehouse = context.options.get(CatalogOptions.WAREHOUSE)
-        self.api = RESTApi(context.options.to_map(), config_required)
-        self.context = CatalogContext.create(Options(self.api.options), 
context.hadoop_conf, context.prefer_io_loader,
-                                             context.fallback_io_loader)
-        self.data_token_enabled = 
self.api.options.get(CatalogOptions.DATA_TOKEN_ENABLED)
+        self.rest_api = RESTApi(context.options.to_map(), config_required)
+        self.context = CatalogContext.create(Options(self.rest_api.options), 
context.hadoop_conf,
+                                             context.prefer_io_loader, 
context.fallback_io_loader)
+        self.data_token_enabled = 
self.rest_api.options.get(CatalogOptions.DATA_TOKEN_ENABLED)
 
     def catalog_loader(self):
         """
@@ -91,7 +92,7 @@ class RESTCatalog(Catalog):
             TableNotExistException: If the target table does not exist
         """
         try:
-            return self.api.commit_snapshot(identifier, table_uuid, snapshot, 
statistics)
+            return self.rest_api.commit_snapshot(identifier, table_uuid, 
snapshot, statistics)
         except NoSuchResourceException as e:
             raise TableNotExistException(identifier) from e
         except Exception as e:
@@ -99,17 +100,17 @@ class RESTCatalog(Catalog):
             raise RuntimeError(f"Failed to commit snapshot for table 
{identifier.get_full_name()}: {e}") from e
 
     def list_databases(self) -> List[str]:
-        return self.api.list_databases()
+        return self.rest_api.list_databases()
 
     def list_databases_paged(self, max_results: Optional[int] = None, 
page_token: Optional[str] = None,
                              database_name_pattern: Optional[str] = None) -> 
PagedList[str]:
-        return self.api.list_databases_paged(max_results, page_token, 
database_name_pattern)
+        return self.rest_api.list_databases_paged(max_results, page_token, 
database_name_pattern)
 
     def create_database(self, name: str, ignore_if_exists: bool, properties: 
Dict[str, str] = None):
-        self.api.create_database(name, properties)
+        self.rest_api.create_database(name, properties)
 
     def get_database(self, name: str) -> Database:
-        response = self.api.get_database(name)
+        response = self.rest_api.get_database(name)
         options = response.options
         options[Catalog.DB_LOCATION_PROP] = response.location
         response.put_audit_options_to(options)
@@ -117,14 +118,14 @@ class RESTCatalog(Catalog):
             return Database(name, options)
 
     def drop_database(self, name: str):
-        self.api.drop_database(name)
+        self.rest_api.drop_database(name)
 
     def alter_database(self, name: str, changes: List[PropertyChange]):
         set_properties, remove_keys = 
PropertyChange.get_set_properties_to_remove_keys(changes)
-        self.api.alter_database(name, list(remove_keys), set_properties)
+        self.rest_api.alter_database(name, list(remove_keys), set_properties)
 
     def list_tables(self, database_name: str) -> List[str]:
-        return self.api.list_tables(database_name)
+        return self.rest_api.list_tables(database_name)
 
     def list_tables_paged(
             self,
@@ -133,7 +134,7 @@ class RESTCatalog(Catalog):
             page_token: Optional[str] = None,
             table_name_pattern: Optional[str] = None
     ) -> PagedList[str]:
-        return self.api.list_tables_paged(
+        return self.rest_api.list_tables_paged(
             database_name,
             max_results,
             page_token,
@@ -153,15 +154,15 @@ class RESTCatalog(Catalog):
     def create_table(self, identifier: Union[str, Identifier], schema: Schema, 
ignore_if_exists: bool):
         if not isinstance(identifier, Identifier):
             identifier = Identifier.from_string(identifier)
-        self.api.create_table(identifier, schema)
+        self.rest_api.create_table(identifier, schema)
 
     def drop_table(self, identifier: Union[str, Identifier]):
         if not isinstance(identifier, Identifier):
             identifier = Identifier.from_string(identifier)
-        self.api.drop_table(identifier)
+        self.rest_api.drop_table(identifier)
 
     def load_table_metadata(self, identifier: Identifier) -> TableMetadata:
-        response = self.api.get_table(identifier)
+        response = self.rest_api.get_table(identifier)
         return self.to_table_metadata(identifier.get_database_name(), response)
 
     def to_table_metadata(self, db: str, response: GetTableResponse) -> 
TableMetadata:
diff --git a/paimon-python/pypaimon/catalog/rest/rest_token_file_io.py 
b/paimon-python/pypaimon/catalog/rest/rest_token_file_io.py
index 6142fa6373..b9671c8ae9 100644
--- a/paimon-python/pypaimon/catalog/rest/rest_token_file_io.py
+++ b/paimon-python/pypaimon/catalog/rest/rest_token_file_io.py
@@ -23,7 +23,7 @@ from typing import Optional
 
 from pyarrow._fs import FileSystem
 
-from pypaimon.api import RESTApi
+from pypaimon.api.rest_api import RESTApi
 from pypaimon.catalog.rest.rest_token import RESTToken
 from pypaimon.common.file_io import FileIO
 from pypaimon.common.identifier import Identifier
diff --git a/paimon-python/pypaimon/catalog/table_metadata.py 
b/paimon-python/pypaimon/catalog/rest/table_metadata.py
similarity index 100%
rename from paimon-python/pypaimon/catalog/table_metadata.py
rename to paimon-python/pypaimon/catalog/rest/table_metadata.py
diff --git a/paimon-python/pypaimon/common/identifier.py 
b/paimon-python/pypaimon/common/identifier.py
index 3a27870516..d3a4fcda7f 100644
--- a/paimon-python/pypaimon/common/identifier.py
+++ b/paimon-python/pypaimon/common/identifier.py
@@ -18,7 +18,7 @@
 from dataclasses import dataclass
 from typing import Optional
 
-from pypaimon.common.rest_json import json_field
+from pypaimon.common.json_util import json_field
 
 SYSTEM_TABLE_SPLITTER = '$'
 SYSTEM_BRANCH_PREFIX = 'branch-'
diff --git a/paimon-python/pypaimon/common/rest_json.py 
b/paimon-python/pypaimon/common/json_util.py
similarity index 100%
rename from paimon-python/pypaimon/common/rest_json.py
rename to paimon-python/pypaimon/common/json_util.py
diff --git a/paimon-python/pypaimon/pvfs/__init__.py 
b/paimon-python/pypaimon/pvfs/__init__.py
index 78b3b73691..7e60a558d1 100644
--- a/paimon-python/pypaimon/pvfs/__init__.py
+++ b/paimon-python/pypaimon/pvfs/__init__.py
@@ -29,10 +29,12 @@ from fsspec import AbstractFileSystem
 from fsspec.implementations.local import LocalFileSystem
 from readerwriterlock import rwlock
 
-from pypaimon.api import (GetTableResponse, GetTableTokenResponse, Identifier,
-                          RESTApi, Schema)
+from pypaimon.api.api_response import GetTableTokenResponse, GetTableResponse
 from pypaimon.api.client import AlreadyExistsException, NoSuchResourceException
+from pypaimon.api.rest_api import RESTApi
 from pypaimon.common.config import CatalogOptions, OssOptions, PVFSOptions
+from pypaimon.common.identifier import Identifier
+from pypaimon.schema.schema import Schema
 
 PROTOCOL_NAME = "pvfs"
 
diff --git a/paimon-python/pypaimon/schema/schema.py 
b/paimon-python/pypaimon/schema/schema.py
index 20e0720087..965fe2255b 100644
--- a/paimon-python/pypaimon/schema/schema.py
+++ b/paimon-python/pypaimon/schema/schema.py
@@ -20,7 +20,7 @@ from typing import Dict, List, Optional
 
 import pyarrow as pa
 
-from pypaimon.common.rest_json import json_field
+from pypaimon.common.json_util import json_field
 from pypaimon.schema.data_types import DataField, PyarrowFieldParser
 
 
diff --git a/paimon-python/pypaimon/schema/schema_manager.py 
b/paimon-python/pypaimon/schema/schema_manager.py
index f03b9e111b..2af8481b49 100644
--- a/paimon-python/pypaimon/schema/schema_manager.py
+++ b/paimon-python/pypaimon/schema/schema_manager.py
@@ -19,7 +19,7 @@ from pathlib import Path
 from typing import Optional
 
 from pypaimon.common.file_io import FileIO
-from pypaimon.common.rest_json import JSON
+from pypaimon.common.json_util import JSON
 from pypaimon.schema.schema import Schema
 from pypaimon.schema.table_schema import TableSchema
 
diff --git a/paimon-python/pypaimon/schema/table_schema.py 
b/paimon-python/pypaimon/schema/table_schema.py
index dc1872deb6..852ef8c4ea 100644
--- a/paimon-python/pypaimon/schema/table_schema.py
+++ b/paimon-python/pypaimon/schema/table_schema.py
@@ -24,7 +24,7 @@ from typing import Dict, List, Optional
 
 from pypaimon.common.core_options import CoreOptions
 from pypaimon.common.file_io import FileIO
-from pypaimon.common.rest_json import json_field
+from pypaimon.common.json_util import json_field
 from pypaimon.schema.data_types import DataField
 from pypaimon.schema.schema import Schema
 
diff --git a/paimon-python/pypaimon/catalog/catalog_snapshot_commit.py 
b/paimon-python/pypaimon/snapshot/catalog_snapshot_commit.py
similarity index 95%
rename from paimon-python/pypaimon/catalog/catalog_snapshot_commit.py
rename to paimon-python/pypaimon/snapshot/catalog_snapshot_commit.py
index cc1ed258f8..26796f7766 100644
--- a/paimon-python/pypaimon/catalog/catalog_snapshot_commit.py
+++ b/paimon-python/pypaimon/snapshot/catalog_snapshot_commit.py
@@ -19,9 +19,10 @@
 from typing import List
 
 from pypaimon.catalog.catalog import Catalog
-from pypaimon.catalog.snapshot_commit import PartitionStatistics, 
SnapshotCommit
 from pypaimon.common.identifier import Identifier
 from pypaimon.snapshot.snapshot import Snapshot
+from pypaimon.snapshot.snapshot_commit import (PartitionStatistics,
+                                               SnapshotCommit)
 
 
 class CatalogSnapshotCommit(SnapshotCommit):
diff --git a/paimon-python/pypaimon/catalog/renaming_snapshot_commit.py 
b/paimon-python/pypaimon/snapshot/renaming_snapshot_commit.py
similarity index 95%
rename from paimon-python/pypaimon/catalog/renaming_snapshot_commit.py
rename to paimon-python/pypaimon/snapshot/renaming_snapshot_commit.py
index b85c4200a1..27c5a54a2c 100644
--- a/paimon-python/pypaimon/catalog/renaming_snapshot_commit.py
+++ b/paimon-python/pypaimon/snapshot/renaming_snapshot_commit.py
@@ -18,10 +18,11 @@
 
 from typing import List
 
-from pypaimon.catalog.snapshot_commit import PartitionStatistics, 
SnapshotCommit
 from pypaimon.common.file_io import FileIO
-from pypaimon.common.rest_json import JSON
+from pypaimon.common.json_util import JSON
 from pypaimon.snapshot.snapshot import Snapshot
+from pypaimon.snapshot.snapshot_commit import (PartitionStatistics,
+                                               SnapshotCommit)
 from pypaimon.snapshot.snapshot_manager import SnapshotManager
 
 
diff --git a/paimon-python/pypaimon/snapshot/snapshot.py 
b/paimon-python/pypaimon/snapshot/snapshot.py
index cc27c5a530..5bc92dcad4 100644
--- a/paimon-python/pypaimon/snapshot/snapshot.py
+++ b/paimon-python/pypaimon/snapshot/snapshot.py
@@ -19,7 +19,7 @@
 from dataclasses import dataclass
 from typing import Dict, Optional
 
-from pypaimon.common.rest_json import json_field
+from pypaimon.common.json_util import json_field
 
 
 @dataclass
diff --git a/paimon-python/pypaimon/catalog/snapshot_commit.py 
b/paimon-python/pypaimon/snapshot/snapshot_commit.py
similarity index 98%
rename from paimon-python/pypaimon/catalog/snapshot_commit.py
rename to paimon-python/pypaimon/snapshot/snapshot_commit.py
index f66b123343..50727b6ce3 100644
--- a/paimon-python/pypaimon/catalog/snapshot_commit.py
+++ b/paimon-python/pypaimon/snapshot/snapshot_commit.py
@@ -16,12 +16,12 @@
 # limitations under the License.
 
################################################################################
 
+import time
 from abc import ABC, abstractmethod
 from dataclasses import dataclass
 from typing import Dict, List
-import time
 
-from pypaimon.common.rest_json import json_field
+from pypaimon.common.json_util import json_field
 from pypaimon.snapshot.snapshot import Snapshot
 
 
diff --git a/paimon-python/pypaimon/snapshot/snapshot_manager.py 
b/paimon-python/pypaimon/snapshot/snapshot_manager.py
index f23ad03dae..2ded357802 100644
--- a/paimon-python/pypaimon/snapshot/snapshot_manager.py
+++ b/paimon-python/pypaimon/snapshot/snapshot_manager.py
@@ -19,7 +19,7 @@ from pathlib import Path
 from typing import Optional
 
 from pypaimon.common.file_io import FileIO
-from pypaimon.common.rest_json import JSON
+from pypaimon.common.json_util import JSON
 from pypaimon.snapshot.snapshot import Snapshot
 
 
diff --git a/paimon-python/pypaimon/table/file_store_table.py 
b/paimon-python/pypaimon/table/file_store_table.py
index eb763d2938..74aaaff4e6 100644
--- a/paimon-python/pypaimon/table/file_store_table.py
+++ b/paimon-python/pypaimon/table/file_store_table.py
@@ -19,6 +19,7 @@
 from pathlib import Path
 from typing import Optional
 
+from pypaimon.catalog.catalog_environment import CatalogEnvironment
 from pypaimon.common.core_options import CoreOptions
 from pypaimon.common.file_io import FileIO
 from pypaimon.common.identifier import Identifier
@@ -26,7 +27,6 @@ from pypaimon.read.read_builder import ReadBuilder
 from pypaimon.schema.schema_manager import SchemaManager
 from pypaimon.schema.table_schema import TableSchema
 from pypaimon.table.bucket_mode import BucketMode
-from pypaimon.table.catalog_environment import CatalogEnvironment
 from pypaimon.table.table import Table
 from pypaimon.write.batch_write_builder import BatchWriteBuilder
 from pypaimon.write.row_key_extractor import (DynamicBucketRowKeyExtractor,
diff --git a/paimon-python/pypaimon/tests/api_test.py 
b/paimon-python/pypaimon/tests/api_test.py
index 6de26917eb..c63b912635 100644
--- a/paimon-python/pypaimon/tests/api_test.py
+++ b/paimon-python/pypaimon/tests/api_test.py
@@ -19,20 +19,19 @@ import logging
 import unittest
 import uuid
 
-import pypaimon.api as api
+from pypaimon.api.api_response import ConfigResponse
+from pypaimon.api.auth import BearTokenAuthProvider
+from pypaimon.api.rest_api import RESTApi
+from pypaimon.api.token_loader import DLFToken, DLFTokenLoaderFactory
+from pypaimon.catalog.rest.table_metadata import TableMetadata
+from pypaimon.common.config import CatalogOptions
 from pypaimon.common.identifier import Identifier
-from pypaimon.common.rest_json import JSON
+from pypaimon.common.json_util import JSON
 from pypaimon.schema.data_types import (ArrayType, AtomicInteger, AtomicType,
                                         DataField, DataTypeParser, MapType,
                                         RowType)
 from pypaimon.schema.table_schema import TableSchema
-
-from ..api import RESTApi
-from ..api.api_response import ConfigResponse
-from ..api.auth import BearTokenAuthProvider
-from ..api.token_loader import DLFToken, DLFTokenLoaderFactory
-from ..catalog.table_metadata import TableMetadata
-from .rest_server import RESTCatalogServer
+from pypaimon.tests.rest_server import RESTCatalogServer
 
 
 class ApiTestCase(unittest.TestCase):
@@ -170,10 +169,10 @@ class ApiTestCase(unittest.TestCase):
                 "token.provider": "bear",
                 'token': token
             }
-            api = RESTApi(options)
-            self.assertSetEqual(set(api.list_databases()), {*test_databases})
-            self.assertEqual(api.get_database('default'), 
test_databases.get('default'))
-            table = api.get_table(Identifier.from_string('default.user'))
+            rest_api = RESTApi(options)
+            self.assertSetEqual(set(rest_api.list_databases()), 
{*test_databases})
+            self.assertEqual(rest_api.get_database('default'), 
test_databases.get('default'))
+            table = rest_api.get_table(Identifier.from_string('default.user'))
             self.assertEqual(table.id, str(test_tables['default.user'].uuid))
 
         finally:
@@ -204,8 +203,8 @@ class ApiTestCase(unittest.TestCase):
             server.start()
             ecs_metadata_url = 
f"http://localhost:{server.port}/ram/security-credential/";
             options = {
-                api.CatalogOptions.DLF_TOKEN_LOADER: 'ecs',
-                api.CatalogOptions.DLF_TOKEN_ECS_METADATA_URL: ecs_metadata_url
+                CatalogOptions.DLF_TOKEN_LOADER: 'ecs',
+                CatalogOptions.DLF_TOKEN_ECS_METADATA_URL: ecs_metadata_url
             }
             loader = DLFTokenLoaderFactory.create_token_loader(options)
             load_token = loader.load_token()
@@ -214,9 +213,9 @@ class ApiTestCase(unittest.TestCase):
             self.assertEqual(load_token.security_token, token.security_token)
             self.assertEqual(load_token.expiration, token.expiration)
             options_with_role = {
-                api.CatalogOptions.DLF_TOKEN_LOADER: 'ecs',
-                api.CatalogOptions.DLF_TOKEN_ECS_METADATA_URL: 
ecs_metadata_url,
-                api.CatalogOptions.DLF_TOKEN_ECS_ROLE_NAME: role_name,
+                CatalogOptions.DLF_TOKEN_LOADER: 'ecs',
+                CatalogOptions.DLF_TOKEN_ECS_METADATA_URL: ecs_metadata_url,
+                CatalogOptions.DLF_TOKEN_ECS_ROLE_NAME: role_name,
             }
             loader = 
DLFTokenLoaderFactory.create_token_loader(options_with_role)
             token = loader.load_token()
diff --git a/paimon-python/pypaimon/tests/predicates_test.py 
b/paimon-python/pypaimon/tests/predicates_test.py
index 5ce806bbcb..19d101fb28 100644
--- a/paimon-python/pypaimon/tests/predicates_test.py
+++ b/paimon-python/pypaimon/tests/predicates_test.py
@@ -23,8 +23,8 @@ import unittest
 import pandas as pd
 import pyarrow as pa
 
-from pypaimon.api import Schema
 from pypaimon.catalog.catalog_factory import CatalogFactory
+from pypaimon.schema.schema import Schema
 
 
 def _check_filtered_result(read_builder, expected_df):
diff --git a/paimon-python/pypaimon/tests/pvfs_test.py 
b/paimon-python/pypaimon/tests/pvfs_test.py
index 3f80d1eb63..8bebb9855d 100644
--- a/paimon-python/pypaimon/tests/pvfs_test.py
+++ b/paimon-python/pypaimon/tests/pvfs_test.py
@@ -23,9 +23,9 @@ from pathlib import Path
 
 import pandas
 
-from pypaimon.api import ConfigResponse
+from pypaimon.api.api_response import ConfigResponse
 from pypaimon.api.auth import BearTokenAuthProvider
-from pypaimon.catalog.table_metadata import TableMetadata
+from pypaimon.catalog.rest.table_metadata import TableMetadata
 from pypaimon.pvfs import PaimonVirtualFileSystem
 from pypaimon.schema.data_types import AtomicType, DataField
 from pypaimon.schema.table_schema import TableSchema
diff --git a/paimon-python/pypaimon/tests/reader_append_only_test.py 
b/paimon-python/pypaimon/tests/reader_append_only_test.py
index f82f28d7a0..17acb9a183 100644
--- a/paimon-python/pypaimon/tests/reader_append_only_test.py
+++ b/paimon-python/pypaimon/tests/reader_append_only_test.py
@@ -22,8 +22,8 @@ import unittest
 
 import pyarrow as pa
 
-from pypaimon.api import Schema
 from pypaimon.catalog.catalog_factory import CatalogFactory
+from pypaimon.schema.schema import Schema
 
 
 class AoReaderTest(unittest.TestCase):
diff --git a/paimon-python/pypaimon/tests/reader_primary_key_test.py 
b/paimon-python/pypaimon/tests/reader_primary_key_test.py
index b9b115dfa4..8b9b853350 100644
--- a/paimon-python/pypaimon/tests/reader_primary_key_test.py
+++ b/paimon-python/pypaimon/tests/reader_primary_key_test.py
@@ -23,8 +23,8 @@ import unittest
 
 import pyarrow as pa
 
-from pypaimon.api import Schema
 from pypaimon.catalog.catalog_factory import CatalogFactory
+from pypaimon.schema.schema import Schema
 
 
 class PkReaderTest(unittest.TestCase):
diff --git a/paimon-python/pypaimon/tests/rest_catalog_base_test.py 
b/paimon-python/pypaimon/tests/rest_catalog_base_test.py
index c035957ccc..e56580e0ae 100644
--- a/paimon-python/pypaimon/tests/rest_catalog_base_test.py
+++ b/paimon-python/pypaimon/tests/rest_catalog_base_test.py
@@ -25,13 +25,14 @@ import uuid
 
 import pyarrow as pa
 
-from pypaimon.api import ConfigResponse, Identifier
+from pypaimon.api.api_response import ConfigResponse
 from pypaimon.api.auth import BearTokenAuthProvider
 from pypaimon.api.options import Options
 from pypaimon.catalog.catalog_context import CatalogContext
 from pypaimon.catalog.catalog_factory import CatalogFactory
 from pypaimon.catalog.rest.rest_catalog import RESTCatalog
-from pypaimon.catalog.table_metadata import TableMetadata
+from pypaimon.catalog.rest.table_metadata import TableMetadata
+from pypaimon.common.identifier import Identifier
 from pypaimon.schema.data_types import (ArrayType, AtomicType, DataField,
                                         MapType)
 from pypaimon.schema.schema import Schema
diff --git a/paimon-python/pypaimon/tests/rest_server.py 
b/paimon-python/pypaimon/tests/rest_server.py
index c326f3525d..8804a4f5e2 100644
--- a/paimon-python/pypaimon/tests/rest_server.py
+++ b/paimon-python/pypaimon/tests/rest_server.py
@@ -27,22 +27,24 @@ from pathlib import Path
 from typing import Any, Dict, List, Optional, Tuple, Union
 from urllib.parse import urlparse
 
-import pypaimon.api as api
-from pypaimon.common.rest_json import JSON
+from pypaimon.api.api_request import (CreateDatabaseRequest,
+                                      CreateTableRequest, RenameTableRequest)
+from pypaimon.api.api_response import (ConfigResponse, GetDatabaseResponse,
+                                       GetTableResponse, ListDatabasesResponse,
+                                       ListTablesResponse, PagedList,
+                                       RESTResponse)
+from pypaimon.api.resource_paths import ResourcePaths
+from pypaimon.api.rest_util import RESTUtil
+from pypaimon.catalog.catalog_exception import (DatabaseNoPermissionException,
+                                                DatabaseNotExistException,
+                                                TableNoPermissionException,
+                                                TableNotExistException)
+from pypaimon.catalog.rest.table_metadata import TableMetadata
+from pypaimon.common.identifier import Identifier
+from pypaimon.common.json_util import JSON
+from pypaimon.schema.schema import Schema
 from pypaimon.schema.table_schema import TableSchema
 
-from ..api import (CreateDatabaseRequest, CreateTableRequest, Identifier,
-                   RenameTableRequest)
-from ..api.api_response import (ConfigResponse, GetDatabaseResponse,
-                                GetTableResponse, ListDatabasesResponse,
-                                ListTablesResponse, PagedList, RESTResponse)
-from ..catalog.catalog_exception import (DatabaseNoPermissionException,
-                                         DatabaseNotExistException,
-                                         TableNoPermissionException,
-                                         TableNotExistException)
-from ..catalog.table_metadata import TableMetadata
-from ..schema.schema import Schema
-
 
 @dataclass
 class ErrorResponse(RESTResponse):
@@ -99,7 +101,7 @@ class RESTCatalogServer:
 
         # Initialize resource paths
         prefix = config.defaults.get("prefix")
-        self.resource_paths = api.ResourcePaths(prefix=prefix)
+        self.resource_paths = ResourcePaths(prefix=prefix)
         self.database_uri = self.resource_paths.databases()
 
         # Initialize storage
@@ -199,7 +201,7 @@ class RESTCatalogServer:
                 for pair in query.split('&'):
                     if '=' in pair:
                         key, value = pair.split('=', 1)
-                        params[key.strip()] = 
api.RESTUtil.decode_string(value.strip())
+                        params[key.strip()] = 
RESTUtil.decode_string(value.strip())
                 return params
 
             def _authenticate(self, token: str, path: str, params: Dict[str, 
str],
@@ -265,7 +267,7 @@ class RESTCatalogServer:
                 """Handle database-specific resource requests"""
                 # Extract database name and resource path
                 path_parts = resource_path[len(self.database_uri) + 
1:].split('/')
-                database_name = api.RESTUtil.decode_string(path_parts[0])
+                database_name = RESTUtil.decode_string(path_parts[0])
 
                 # Check database permissions
                 if database_name in self.no_permission_databases:
@@ -283,16 +285,16 @@ class RESTCatalogServer:
                     # Collection operations (tables, views, functions)
                     resource_type = path_parts[1]
 
-                    if resource_type.startswith(api.ResourcePaths.TABLES):
+                    if resource_type.startswith(ResourcePaths.TABLES):
                         return self._tables_handle(method, data, 
database_name, parameters)
 
                 elif len(path_parts) >= 3:
                     # Individual resource operations
                     resource_type = path_parts[1]
-                    resource_name = api.RESTUtil.decode_string(path_parts[2])
+                    resource_name = RESTUtil.decode_string(path_parts[2])
                     identifier = Identifier.create(database_name, 
resource_name)
 
-                    if resource_type == api.ResourcePaths.TABLES:
+                    if resource_type == ResourcePaths.TABLES:
                         return self._handle_table_resource(method, path_parts, 
identifier, data, parameters)
 
                 return self._mock_response(ErrorResponse(None, None, "Not 
Found", 404), 404)
diff --git a/paimon-python/pypaimon/tests/test_file_store_commit.py 
b/paimon-python/pypaimon/tests/test_file_store_commit.py
index ced0afbf4a..6f32894c90 100644
--- a/paimon-python/pypaimon/tests/test_file_store_commit.py
+++ b/paimon-python/pypaimon/tests/test_file_store_commit.py
@@ -21,8 +21,8 @@ from datetime import datetime
 from pathlib import Path
 from unittest.mock import Mock, patch
 
-from pypaimon.catalog.snapshot_commit import PartitionStatistics
 from pypaimon.manifest.schema.data_file_meta import DataFileMeta
+from pypaimon.snapshot.snapshot_commit import PartitionStatistics
 from pypaimon.write.commit_message import CommitMessage
 from pypaimon.write.file_store_commit import FileStoreCommit
 
diff --git a/paimon-python/pypaimon/tests/test_rest_catalog_commit_snapshot.py 
b/paimon-python/pypaimon/tests/test_rest_catalog_commit_snapshot.py
index 25350ebea0..84c6557c1e 100644
--- a/paimon-python/pypaimon/tests/test_rest_catalog_commit_snapshot.py
+++ b/paimon-python/pypaimon/tests/test_rest_catalog_commit_snapshot.py
@@ -22,15 +22,15 @@ import time
 import unittest
 from unittest.mock import Mock, patch
 
-from pypaimon.api import NoSuchResourceException
 from pypaimon.api.api_response import CommitTableResponse
 from pypaimon.api.options import Options
+from pypaimon.api.rest_exception import NoSuchResourceException
 from pypaimon.catalog.catalog_context import CatalogContext
 from pypaimon.catalog.catalog_exception import TableNotExistException
 from pypaimon.catalog.rest.rest_catalog import RESTCatalog
-from pypaimon.catalog.snapshot_commit import PartitionStatistics
 from pypaimon.common.identifier import Identifier
 from pypaimon.snapshot.snapshot import Snapshot
+from pypaimon.snapshot.snapshot_commit import PartitionStatistics
 
 
 class TestRESTCatalogCommitSnapshot(unittest.TestCase):
@@ -120,7 +120,7 @@ class TestRESTCatalogCommitSnapshot(unittest.TestCase):
             # Configure mock to raise NoSuchResourceException
             mock_api_instance = Mock()
             mock_api_instance.options = self.test_options
-            mock_api_instance.commit_snapshot.side_effect = 
NoSuchResourceException("Table not found")
+            mock_api_instance.commit_snapshot.side_effect = 
NoSuchResourceException("Table", None, "not found")
             mock_rest_api.return_value = mock_api_instance
 
             # Create RESTCatalog
@@ -188,9 +188,9 @@ class TestRESTCatalogCommitSnapshot(unittest.TestCase):
 
     def test_rest_api_commit_snapshot(self):
         """Test RESTApi commit_snapshot method."""
-        from pypaimon.api import RESTApi
+        from pypaimon.api.rest_api import RESTApi
 
-        with patch('pypaimon.api.HttpClient') as mock_client_class:
+        with patch('pypaimon.api.client.HttpClient') as mock_client_class:
             # Configure mock
             mock_client = Mock()
             mock_response = CommitTableResponse(success=True)
diff --git a/paimon-python/pypaimon/write/commit_message.py 
b/paimon-python/pypaimon/write/commit_message.py
index 4e4c0f0b48..b36a1b1bbf 100644
--- a/paimon-python/pypaimon/write/commit_message.py
+++ b/paimon-python/pypaimon/write/commit_message.py
@@ -15,6 +15,7 @@
 #  See the License for the specific language governing permissions and
 # limitations under the License.
 
################################################################################
+
 from dataclasses import dataclass
 from typing import List, Tuple
 
diff --git a/paimon-python/pypaimon/write/file_store_commit.py 
b/paimon-python/pypaimon/write/file_store_commit.py
index ca26981333..e7bf7ba534 100644
--- a/paimon-python/pypaimon/write/file_store_commit.py
+++ b/paimon-python/pypaimon/write/file_store_commit.py
@@ -21,12 +21,13 @@ import uuid
 from pathlib import Path
 from typing import List
 
-from pypaimon.catalog.snapshot_commit import PartitionStatistics, 
SnapshotCommit
 from pypaimon.manifest.manifest_file_manager import ManifestFileManager
 from pypaimon.manifest.manifest_list_manager import ManifestListManager
 from pypaimon.manifest.schema.manifest_file_meta import ManifestFileMeta
 from pypaimon.manifest.schema.simple_stats import SimpleStats
 from pypaimon.snapshot.snapshot import Snapshot
+from pypaimon.snapshot.snapshot_commit import (PartitionStatistics,
+                                               SnapshotCommit)
 from pypaimon.snapshot.snapshot_manager import SnapshotManager
 from pypaimon.table.row.binary_row import BinaryRow
 from pypaimon.write.commit_message import CommitMessage
diff --git a/paimon-python/pypaimon/write/row_key_extractor.py 
b/paimon-python/pypaimon/write/row_key_extractor.py
index bec8e08fb7..aa28aacef2 100644
--- a/paimon-python/pypaimon/write/row_key_extractor.py
+++ b/paimon-python/pypaimon/write/row_key_extractor.py
@@ -15,6 +15,7 @@
 #  See the License for the specific language governing permissions and
 # limitations under the License.
 
################################################################################
+
 import hashlib
 import json
 from abc import ABC, abstractmethod

Reply via email to