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/04/27 06:32:17 UTC

(paimon) branch master updated: [python] Fix pathlib.Path producing backslashes paths on Windows (#7700)

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 cec7050bfb [python] Fix pathlib.Path producing backslashes paths on Windows (#7700)
cec7050bfb is described below

commit cec7050bfb1b43e5e5f8e842116520c91f8c2526
Author: XiaoHongbo <xi...@alibaba-inc.com>
AuthorDate: Mon Apr 27 14:32:12 2026 +0800

    [python] Fix pathlib.Path producing backslashes paths on Windows (#7700)
---
 .../pypaimon/filesystem/pyarrow_file_io.py         | 12 +++++------
 paimon-python/pypaimon/tests/file_io_test.py       | 25 ++++++++++++++++++++++
 2 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/paimon-python/pypaimon/filesystem/pyarrow_file_io.py b/paimon-python/pypaimon/filesystem/pyarrow_file_io.py
index db06eb6f99..b5e03c0151 100644
--- a/paimon-python/pypaimon/filesystem/pyarrow_file_io.py
+++ b/paimon-python/pypaimon/filesystem/pyarrow_file_io.py
@@ -21,7 +21,7 @@ import re
 import subprocess
 import uuid
 from datetime import datetime, timezone
-from pathlib import Path
+from pathlib import PurePosixPath
 from typing import Any, Dict, List, Optional
 from urllib.parse import splitport, urlparse
 
@@ -235,7 +235,7 @@ class PyArrowFileIO(FileIO):
             if parent_dir and not self.exists(parent_dir):
                 self.mkdirs(parent_dir)
         else:
-            parent_dir = Path(path_str).parent
+            parent_dir = PurePosixPath(path_str).parent
             if str(parent_dir) and not self.exists(str(parent_dir)):
                 self.mkdirs(str(parent_dir))
 
@@ -326,7 +326,7 @@ class PyArrowFileIO(FileIO):
 
     def rename(self, src: str, dst: str) -> bool:
         dst_str = self.to_filesystem_path(dst)
-        dst_parent = Path(dst_str).parent
+        dst_parent = PurePosixPath(dst_str).parent
         if str(dst_parent) and not self.exists(str(dst_parent)):
             self.mkdirs(str(dst_parent))
 
@@ -342,8 +342,8 @@ class PyArrowFileIO(FileIO):
                     return False
                 # Make it compatible with HadoopFileIO: if dst is an existing directory,
                 # dst=dst/srcFileName
-                src_name = Path(src_str).name
-                dst_str = str(Path(dst_str) / src_name)
+                src_name = PurePosixPath(src_str).name
+                dst_str = str(PurePosixPath(dst_str) / src_name)
                 final_dst_info = self._get_file_info(dst_str)
                 if final_dst_info.type != pafs.FileType.NotFound:
                     return False
@@ -402,7 +402,7 @@ class PyArrowFileIO(FileIO):
 
         source_str = self.to_filesystem_path(source_path)
         target_str = self.to_filesystem_path(target_path)
-        target_parent = Path(target_str).parent
+        target_parent = PurePosixPath(target_str).parent
 
         if str(target_parent) and not self.exists(str(target_parent)):
             self.mkdirs(str(target_parent))
diff --git a/paimon-python/pypaimon/tests/file_io_test.py b/paimon-python/pypaimon/tests/file_io_test.py
index d39d0c6461..86c4c28f82 100644
--- a/paimon-python/pypaimon/tests/file_io_test.py
+++ b/paimon-python/pypaimon/tests/file_io_test.py
@@ -464,5 +464,30 @@ class FileIOTest(unittest.TestCase):
         finally:
             shutil.rmtree(temp_dir, ignore_errors=True)
 
+    def test_path_on_windows(self):
+        oss_io = PyArrowFileIO("oss://test-bucket/warehouse", Options({
+            OssOptions.OSS_ENDPOINT.key(): 'oss-cn-hangzhou.aliyuncs.com',
+            OssOptions.OSS_ACCESS_KEY_ID.key(): 'test-key',
+            OssOptions.OSS_ACCESS_KEY_SECRET.key(): 'test-secret',
+            OssOptions.OSS_IMPL.key(): 'legacy',
+        }))
+        mock_fs = MagicMock()
+        mock_fs.get_file_info.return_value = [MagicMock(type=pafs.FileType.NotFound)]
+        mock_fs.create_dir = MagicMock()
+        mock_fs.open_output_stream.return_value = MagicMock()
+        mock_fs.move = MagicMock()
+        mock_fs.copy_file = MagicMock()
+        oss_io.filesystem = mock_fs
+
+        oss_io.new_output_stream("oss://test-bucket/db.db/tbl/bucket-0/data.parquet")
+        oss_io.rename("oss://test-bucket/db.db/tbl/old.parquet",
+                      "oss://test-bucket/db.db/tbl/new.parquet")
+        oss_io.copy_file("oss://test-bucket/db.db/tbl/src.parquet",
+                         "oss://test-bucket/db.db/tbl/dst.parquet")
+
+        for call in mock_fs.create_dir.call_args_list:
+            self.assertNotIn("\\", call[0][0], f"backslash in path: {call[0][0]}")
+
+
 if __name__ == '__main__':
     unittest.main()