File tree Expand file tree Collapse file tree 4 files changed +53
-3
lines changed Expand file tree Collapse file tree 4 files changed +53
-3
lines changed Original file line number Diff line number Diff line change @@ -480,7 +480,5 @@ cdef class HdfsFile(NativeFile):
480480 object mode
481481 object parent
482482
483- cdef object __weakref__
484-
485483 def __dealloc__ (self ):
486484 self .parent = None
Original file line number Diff line number Diff line change @@ -410,9 +410,21 @@ cdef class PythonFile(NativeFile):
410410 cdef:
411411 object handle
412412
413- def __cinit__ (self , handle , mode = ' w ' ):
413+ def __cinit__ (self , handle , mode = None ):
414414 self .handle = handle
415415
416+ if mode is None :
417+ try :
418+ mode = handle.mode
419+ except AttributeError :
420+ # Not all file-like objects have a mode attribute
421+ # (e.g. BytesIO)
422+ try :
423+ mode = ' w' if handle.writable() else ' r'
424+ except AttributeError :
425+ raise ValueError (" could not infer open mode for file-like "
426+ " object %r , please pass it explicitly"
427+ % (handle,))
416428 if mode.startswith(' w' ):
417429 self .wr_file.reset(new PyOutputStream(handle))
418430 self .is_writable = True
Original file line number Diff line number Diff line change @@ -337,6 +337,7 @@ cdef class NativeFile:
337337 bint is_writable
338338 readonly bint closed
339339 bint own_file
340+ object __weakref__
340341
341342 # By implementing these "virtual" functions (all functions in Cython
342343 # extension classes are technically virtual in the C++ sense) we can expose
Original file line number Diff line number Diff line change 2121import os
2222import pytest
2323import sys
24+ import weakref
2425
2526import numpy as np
2627
@@ -124,6 +125,44 @@ def get_buffer():
124125 assert buf .to_pybytes () == b'sample'
125126 assert buf .parent is not None
126127
128+
129+ def test_python_file_implicit_mode (tmpdir ):
130+ path = os .path .join (str (tmpdir ), 'foo.txt' )
131+ with open (path , 'wb' ) as f :
132+ pf = pa .PythonFile (f )
133+ assert pf .writable ()
134+ assert not pf .readable ()
135+ assert not pf .seekable () # PyOutputStream isn't seekable
136+ f .write (b'foobar\n ' )
137+
138+ with open (path , 'rb' ) as f :
139+ pf = pa .PythonFile (f )
140+ assert pf .readable ()
141+ assert not pf .writable ()
142+ assert pf .seekable ()
143+ assert pf .read () == b'foobar\n '
144+
145+ bio = BytesIO ()
146+ pf = pa .PythonFile (bio )
147+ assert pf .writable ()
148+ assert not pf .readable ()
149+ assert not pf .seekable ()
150+ pf .write (b'foobar\n ' )
151+ assert bio .getvalue () == b'foobar\n '
152+
153+
154+ def test_python_file_closing ():
155+ bio = BytesIO ()
156+ pf = pa .PythonFile (bio )
157+ wr = weakref .ref (pf )
158+ del pf
159+ assert wr () is None # object was destroyed
160+ assert not bio .closed
161+ pf = pa .PythonFile (bio )
162+ pf .close ()
163+ assert bio .closed
164+
165+
127166# ----------------------------------------------------------------------
128167# Buffers
129168
You can’t perform that action at this time.
0 commit comments