@@ -16,6 +16,7 @@ import (
1616)
1717
1818var FileType = NewType ("file" , `represents an open file` )
19+ var errClosed = ExceptionNewf (ValueError , "I/O operation on closed file." )
1920
2021func init () {
2122 FileType .Dict ["write" ] = MustNewMethod ("write" , func (self Object , value Object ) (Object , error ) {
@@ -28,6 +29,9 @@ func init() {
2829 FileType .Dict ["close" ] = MustNewMethod ("close" , func (self Object ) (Object , error ) {
2930 return self .(* File ).Close ()
3031 }, 0 , "close() -> None or (perhaps) an integer. Close the file.\n \n Sets data attribute .closed to True. A closed file cannot be used for\n further I/O operations. close() may be called more than once without\n error. Some kinds of file objects (for example, opened by popen())\n may return an exit status upon closing." )
32+ FileType .Dict ["flush" ] = MustNewMethod ("flush" , func (self Object ) (Object , error ) {
33+ return self .(* File ).Flush ()
34+ }, 0 , "flush() -> Flush the write buffers of the stream if applicable. This does nothing for read-only and non-blocking streams." )
3135}
3236
3337type FileMode int
@@ -71,6 +75,9 @@ func (o *File) Write(value Object) (Object, error) {
7175 }
7276
7377 n , err := o .File .Write (b )
78+ if err != nil && err .(* os.PathError ).Err == os .ErrClosed {
79+ return nil , errClosed
80+ }
7481 return Int (n ), err
7582}
7683
@@ -123,10 +130,14 @@ func (o *File) Read(args Tuple, kwargs StringDict) (Object, error) {
123130 }
124131
125132 b , err := ioutil .ReadAll (r )
126- if err == io .EOF {
127- return o .readResult (nil )
128- }
129133 if err != nil {
134+ if err == io .EOF {
135+ return o .readResult (nil )
136+ }
137+ if perr , ok := err .(* os.PathError ); ok && perr .Err == os .ErrClosed {
138+ return nil , errClosed
139+ }
140+
130141 return nil , err
131142 }
132143
@@ -138,6 +149,23 @@ func (o *File) Close() (Object, error) {
138149 return None , nil
139150}
140151
152+ func (o * File ) Flush () (Object , error ) {
153+ err := o .File .Sync ()
154+ if perr , ok := err .(* os.PathError ); ok && perr .Err == os .ErrClosed {
155+ return nil , errClosed
156+ }
157+
158+ return None , nil
159+ }
160+
161+ func (o * File ) M__enter__ () (Object , error ) {
162+ return o , nil
163+ }
164+
165+ func (o * File ) M__exit__ (exc_type , exc_value , traceback Object ) (Object , error ) {
166+ return o .Close ()
167+ }
168+
141169func OpenFile (filename , mode string , buffering int ) (Object , error ) {
142170 var fileMode FileMode
143171 var truncate bool
@@ -177,8 +205,8 @@ func OpenFile(filename, mode string, buffering int) (Object, error) {
177205 return nil , ExceptionNewf (ValueError , "Must have exactly one of create/read/write/append mode and at most one plus" )
178206 }
179207
208+ truncate = (fileMode & FileWrite ) != 0
180209 fileMode |= FileReadWrite
181- truncate = false
182210
183211 case 'b' :
184212 if fileMode & FileReadWrite == 0 {
@@ -229,14 +257,15 @@ func OpenFile(filename, mode string, buffering int) (Object, error) {
229257
230258 f , err := os .OpenFile (filename , fmode , 0666 )
231259 if err != nil {
232- // XXX: should check for different types of errors
233260 switch {
234261 case os .IsExist (err ):
235262 return nil , ExceptionNewf (FileExistsError , err .Error ())
236263
237264 case os .IsNotExist (err ):
238265 return nil , ExceptionNewf (FileNotFoundError , err .Error ())
239266 }
267+
268+ return nil , ExceptionNewf (OSError , err .Error ())
240269 }
241270
242271 if finfo , err := f .Stat (); err == nil {
@@ -250,3 +279,5 @@ func OpenFile(filename, mode string, buffering int) (Object, error) {
250279}
251280
252281// Check interface is satisfied
282+ var _ I__enter__ = (* File )(nil )
283+ var _ I__exit__ = (* File )(nil )
0 commit comments