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

wesm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/master by this push:
     new 524b522  ARROW-2218: [Python] PythonFile should infer mode when not 
given
524b522 is described below

commit 524b5221d2c977f2fa8284ed72d6bbb51dedcb69
Author: Antoine Pitrou <[email protected]>
AuthorDate: Wed Feb 28 14:04:49 2018 -0500

    ARROW-2218: [Python] PythonFile should infer mode when not given
    
    Author: Antoine Pitrou <[email protected]>
    
    Closes #1674 from pitrou/ARROW-2218-infer-python-file-mode and squashes the 
following commits:
    
    a5d704e8 <Antoine Pitrou> ARROW-2218:  PythonFile should infer mode when 
not given
---
 python/pyarrow/io-hdfs.pxi      |  2 --
 python/pyarrow/io.pxi           | 14 +++++++++++++-
 python/pyarrow/lib.pxd          |  1 +
 python/pyarrow/tests/test_io.py | 39 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 53 insertions(+), 3 deletions(-)

diff --git a/python/pyarrow/io-hdfs.pxi b/python/pyarrow/io-hdfs.pxi
index dc6ba23..31c0437 100644
--- a/python/pyarrow/io-hdfs.pxi
+++ b/python/pyarrow/io-hdfs.pxi
@@ -480,7 +480,5 @@ cdef class HdfsFile(NativeFile):
         object mode
         object parent
 
-    cdef object __weakref__
-
     def __dealloc__(self):
         self.parent = None
diff --git a/python/pyarrow/io.pxi b/python/pyarrow/io.pxi
index 8b364dc..0b444cd 100644
--- a/python/pyarrow/io.pxi
+++ b/python/pyarrow/io.pxi
@@ -410,9 +410,21 @@ cdef class PythonFile(NativeFile):
     cdef:
         object handle
 
-    def __cinit__(self, handle, mode='w'):
+    def __cinit__(self, handle, mode=None):
         self.handle = handle
 
+        if mode is None:
+            try:
+                mode = handle.mode
+            except AttributeError:
+                # Not all file-like objects have a mode attribute
+                # (e.g. BytesIO)
+                try:
+                    mode = 'w' if handle.writable() else 'r'
+                except AttributeError:
+                    raise ValueError("could not infer open mode for file-like "
+                                     "object %r, please pass it explicitly"
+                                     % (handle,))
         if mode.startswith('w'):
             self.wr_file.reset(new PyOutputStream(handle))
             self.is_writable = True
diff --git a/python/pyarrow/lib.pxd b/python/pyarrow/lib.pxd
index 31732a6..e4d574f 100644
--- a/python/pyarrow/lib.pxd
+++ b/python/pyarrow/lib.pxd
@@ -337,6 +337,7 @@ cdef class NativeFile:
         bint is_writable
         readonly bint closed
         bint own_file
+        object __weakref__
 
     # By implementing these "virtual" functions (all functions in Cython
     # extension classes are technically virtual in the C++ sense) we can expose
diff --git a/python/pyarrow/tests/test_io.py b/python/pyarrow/tests/test_io.py
index 736020f..d269ad0 100644
--- a/python/pyarrow/tests/test_io.py
+++ b/python/pyarrow/tests/test_io.py
@@ -21,6 +21,7 @@ import gc
 import os
 import pytest
 import sys
+import weakref
 
 import numpy as np
 
@@ -124,6 +125,44 @@ def test_bytes_reader_retains_parent_reference():
     assert buf.to_pybytes() == b'sample'
     assert buf.parent is not None
 
+
+def test_python_file_implicit_mode(tmpdir):
+    path = os.path.join(str(tmpdir), 'foo.txt')
+    with open(path, 'wb') as f:
+        pf = pa.PythonFile(f)
+        assert pf.writable()
+        assert not pf.readable()
+        assert not pf.seekable()  # PyOutputStream isn't seekable
+        f.write(b'foobar\n')
+
+    with open(path, 'rb') as f:
+        pf = pa.PythonFile(f)
+        assert pf.readable()
+        assert not pf.writable()
+        assert pf.seekable()
+        assert pf.read() == b'foobar\n'
+
+    bio = BytesIO()
+    pf = pa.PythonFile(bio)
+    assert pf.writable()
+    assert not pf.readable()
+    assert not pf.seekable()
+    pf.write(b'foobar\n')
+    assert bio.getvalue() == b'foobar\n'
+
+
+def test_python_file_closing():
+    bio = BytesIO()
+    pf = pa.PythonFile(bio)
+    wr = weakref.ref(pf)
+    del pf
+    assert wr() is None  # object was destroyed
+    assert not bio.closed
+    pf = pa.PythonFile(bio)
+    pf.close()
+    assert bio.closed
+
+
 # ----------------------------------------------------------------------
 # Buffers
 

-- 
To stop receiving notification emails like this one, please contact
[email protected].

Reply via email to