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 bd9b251076 [python] Fix Blob.from_bytes use wrong FileIO (#8489)
bd9b251076 is described below

commit bd9b251076169224fd6cf8f6514cc9c67c3f101b
Author: umi <[email protected]>
AuthorDate: Tue Jul 7 14:48:43 2026 +0800

    [python] Fix Blob.from_bytes use wrong FileIO (#8489)
---
 paimon-python/pypaimon/table/row/blob.py  | 13 +++++--
 paimon-python/pypaimon/tests/blob_test.py | 61 +++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+), 4 deletions(-)

diff --git a/paimon-python/pypaimon/table/row/blob.py 
b/paimon-python/pypaimon/table/row/blob.py
index eb2f00b764..d1e2e262f6 100644
--- a/paimon-python/pypaimon/table/row/blob.py
+++ b/paimon-python/pypaimon/table/row/blob.py
@@ -391,7 +391,9 @@ class Blob(ABC):
         return BlobView(view_struct)
 
     @staticmethod
-    def from_bytes(data: Optional[bytes], file_io=None, allow_blob_data: bool 
= True) -> Optional['Blob']:
+    def from_bytes(
+            data: Optional[bytes], file_io=None, uri_reader_factory=None, 
allow_blob_data: bool = True,
+    ) -> Optional['Blob']:
         if data is None:
             return None
         if not isinstance(data, (bytes, bytearray)):
@@ -405,10 +407,13 @@ class Blob(ABC):
                 "Expected BlobDescriptor bytes, got raw bytes 
(allow_blob_data=False)"
             )
         if is_descriptor:
-            if file_io is None:
-                raise ValueError("file_io is required to resolve 
BlobDescriptor bytes")
             descriptor = BlobDescriptor.deserialize(data)
-            uri_reader = file_io.uri_reader_factory.create(descriptor.uri)
+            if uri_reader_factory is None:
+                if file_io is None:
+                    raise ValueError("file_io is required to resolve 
BlobDescriptor bytes")
+                uri_reader = UriReader.from_file(file_io)
+            else:
+                uri_reader = uri_reader_factory.create(descriptor.uri)
             return BlobRef(uri_reader, descriptor)
         return BlobData(data)
 
diff --git a/paimon-python/pypaimon/tests/blob_test.py 
b/paimon-python/pypaimon/tests/blob_test.py
index ac31c399f3..14508d1e10 100644
--- a/paimon-python/pypaimon/tests/blob_test.py
+++ b/paimon-python/pypaimon/tests/blob_test.py
@@ -156,6 +156,67 @@ class BlobTest(unittest.TestCase):
             self.assertIsInstance(blob, BlobRef)
             self.assertEqual(blob.to_data(), data)
 
+    def test_from_bytes_descriptor_uses_explicit_uri_reader_factory(self):
+        data = b"factory blob content"
+        descriptor = BlobDescriptor("custom://bucket/blob.bin", 0, len(data))
+
+        class RecordingUriReader:
+            def __init__(self):
+                self.opened_uris = []
+
+            def new_input_stream(self, uri):
+                self.opened_uris.append(uri)
+                return io.BytesIO(data)
+
+        class RecordingFactory:
+            def __init__(self, reader):
+                self.reader = reader
+                self.created_uris = []
+
+            def create(self, uri):
+                self.created_uris.append(uri)
+                return self.reader
+
+        class FactoryFileIO:
+            def __init__(self, factory):
+                self.uri_reader_factory = factory
+
+            def new_input_stream(self, path):
+                raise AssertionError("from_bytes should use the explicit 
uri_reader_factory")
+
+        reader = RecordingUriReader()
+        factory = RecordingFactory(reader)
+        blob = Blob.from_bytes(
+            descriptor.serialize(), FactoryFileIO(factory), 
uri_reader_factory=factory)
+
+        self.assertEqual(blob.to_data(), data)
+        self.assertEqual(factory.created_uris, [descriptor.uri])
+        self.assertEqual(reader.opened_uris, [descriptor.uri])
+
+    def test_from_bytes_descriptor_can_force_file_io_reader(self):
+        data = b"file backed blob content"
+        descriptor = BlobDescriptor("file-backed/blob.bin", 0, len(data))
+
+        class FailingFactory:
+            def create(self, uri):
+                raise AssertionError("Explicit uri_reader_factory=None should 
skip factory")
+
+        class FileBackedIO:
+            def __init__(self):
+                self.uri_reader_factory = FailingFactory()
+                self.opened_paths = []
+
+            def new_input_stream(self, path):
+                self.opened_paths.append(path)
+                return io.BytesIO(data)
+
+        file_io = FileBackedIO()
+        blob = Blob.from_bytes(
+            descriptor.serialize(), file_io, uri_reader_factory=None)
+
+        self.assertEqual(blob.to_data(), data)
+        self.assertEqual(file_io.opened_paths, [descriptor.uri])
+
     def test_from_bytes_descriptor_without_file_io_raises(self):
         descriptor = BlobDescriptor("/tmp/fake", 0, 10)
         serialized = descriptor.serialize()

Reply via email to