Skip to content

Commit e5b841e

Browse files
committed
Add support for print to file and file flush.
1 parent 8cee534 commit e5b841e

File tree

5 files changed

+106
-16
lines changed

5 files changed

+106
-16
lines changed

‎builtin/builtin.go‎

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
package builtin
77

88
import (
9-
"fmt"
109
"unicode/utf8"
1110

1211
"github.com/go-python/gpython/compile"
@@ -177,7 +176,7 @@ func builtin_print(self py.Object, args py.Tuple, kwargs py.StringDict) (py.Obje
177176
var (
178177
sepObj py.Object=py.String(" ")
179178
endObj py.Object=py.String("\n")
180-
file py.Object
179+
file py.Object=py.MustGetModule("sys").Globals["stdout"]
181180
flush py.Object
182181
)
183182
kwlist:= []string{"sep", "end", "file", "flush"}
@@ -187,19 +186,43 @@ func builtin_print(self py.Object, args py.Tuple, kwargs py.StringDict) (py.Obje
187186
}
188187
sep:=sepObj.(py.String)
189188
end:=endObj.(py.String)
190-
// FIXME ignoring file and flush
189+
190+
write, err:=py.GetAttrString(file, "write")
191+
iferr!=nil{
192+
returnnil, err
193+
}
194+
191195
fori, v:=rangeargs{
192196
v, err:=py.Str(v)
193197
iferr!=nil{
194198
returnnil, err
195199
}
196200

197-
fmt.Printf("%v", v)
201+
_, err=py.Call(write, py.Tuple{v}, nil)
202+
iferr!=nil{
203+
returnnil, err
204+
}
205+
198206
ifi!=len(args)-1{
199-
fmt.Print(sep)
207+
_, err=py.Call(write, py.Tuple{sep}, nil)
208+
iferr!=nil{
209+
returnnil, err
210+
}
200211
}
201212
}
202-
fmt.Print(end)
213+
214+
_, err=py.Call(write, py.Tuple{end}, nil)
215+
iferr!=nil{
216+
returnnil, err
217+
}
218+
219+
ifshouldFlush, _:=py.MakeBool(flush); shouldFlush==py.True{
220+
fflush, err:=py.GetAttrString(file, "flush")
221+
iferr==nil{
222+
py.Call(fflush, nil, nil)
223+
}
224+
}
225+
203226
returnpy.None, nil
204227
}
205228

‎builtin/tests/builtin.py‎

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,42 @@ def gen2():
147147
assertrepr("hello") =="'hello'"
148148

149149
doc="print"
150-
# FIXME - need io redirection to test
151-
#print("hello world")
152-
#print(1,2,3,sep=",",end=",\n")
150+
ok=False
151+
try:
152+
print("hello", sep=1)
153+
exceptTypeErrorase:
154+
#if e.args[0] != "sep must be None or a string, not int":
155+
# raise
156+
ok=True
157+
assertok, "TypeError not raised"
158+
159+
try:
160+
print("hello", sep=" ", end=1)
161+
exceptTypeErrorase:
162+
#if e.args[0] != "end must be None or a string, not int":
163+
# raise
164+
ok=True
165+
assertok, "TypeError not raised"
166+
167+
try:
168+
print("hello", sep=" ", end="\n", file=1)
169+
exceptAttributeErrorase:
170+
#if e.args[0] != "'int' object has no attribute 'write'":
171+
# raise
172+
ok=True
173+
assertok, "AttributeError not raised"
174+
175+
withopen("testfile", "w") asf:
176+
print("hello", "world", sep=" ", end="\n", file=f)
177+
178+
withopen("testfile", "r") asf:
179+
assertf.read() =="hello world\n"
180+
181+
withopen("testfile", "w") asf:
182+
print(1,2,3,sep=",",end=",\n", file=f)
183+
184+
withopen("testfile", "r") asf:
185+
assertf.read() =="1,2,3,\n"
153186

154187
doc="round"
155188
assertround(1.1) ==1.0

‎py/file.go‎

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
)
1717

1818
varFileType=NewType("file", `represents an open file`)
19+
varerrClosed=ExceptionNewf(ValueError, "I/O operation on closed file.")
1920

2021
funcinit(){
2122
FileType.Dict["write"] =MustNewMethod("write", func(selfObject, valueObject) (Object, error){
@@ -28,6 +29,9 @@ func init(){
2829
FileType.Dict["close"] =MustNewMethod("close", func(selfObject) (Object, error){
2930
returnself.(*File).Close()
3031
}, 0, "close() -> None or (perhaps) an integer. Close the file.\n\nSets data attribute .closed to True. A closed file cannot be used for\nfurther I/O operations. close() may be called more than once without\nerror. Some kinds of file objects (for example, opened by popen())\nmay return an exit status upon closing.")
32+
FileType.Dict["flush"] =MustNewMethod("flush", func(selfObject) (Object, error){
33+
returnself.(*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

3337
typeFileModeint
@@ -71,6 +75,9 @@ func (o *File) Write(value Object) (Object, error){
7175
}
7276

7377
n, err:=o.File.Write(b)
78+
iferr!=nil&&err.(*os.PathError).Err==os.ErrClosed{
79+
returnnil, errClosed
80+
}
7481
returnInt(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-
iferr==io.EOF{
127-
returno.readResult(nil)
128-
}
129133
iferr!=nil{
134+
iferr==io.EOF{
135+
returno.readResult(nil)
136+
}
137+
ifperr, ok:=err.(*os.PathError); ok&&perr.Err==os.ErrClosed{
138+
returnnil, errClosed
139+
}
140+
130141
returnnil, err
131142
}
132143

@@ -138,6 +149,24 @@ func (o *File) Close() (Object, error){
138149
returnNone, nil
139150
}
140151

152+
func (o*File) Flush() (Object, error){
153+
err:=o.File.Sync()
154+
ifperr, ok:=err.(*os.PathError); ok&&perr.Err==os.ErrClosed{
155+
returnnil, errClosed
156+
}
157+
158+
returnNone, nil
159+
}
160+
161+
func (o*File) M__enter__() (Object, error){
162+
returno, nil
163+
}
164+
165+
func (o*File) M__exit__(exc_type, exc_value, tracebackObject) (Object, error){
166+
o.Close()
167+
returnNone, nil
168+
}
169+
141170
funcOpenFile(filename, modestring, bufferingint) (Object, error){
142171
varfileModeFileMode
143172
vartruncatebool
@@ -177,8 +206,8 @@ func OpenFile(filename, mode string, buffering int) (Object, error){
177206
returnnil, ExceptionNewf(ValueError, "Must have exactly one of create/read/write/append mode and at most one plus")
178207
}
179208

209+
truncate= (fileMode&FileWrite) !=0
180210
fileMode|=FileReadWrite
181-
truncate=false
182211

183212
case'b':
184213
iffileMode&FileReadWrite==0{
@@ -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)

‎py/tests/file.py‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,13 @@
3535
assertn==5
3636

3737
doc="close"
38-
f.close()
38+
assertf.close() ==None
39+
40+
assertRaises(ValueError, f.read, 1)
41+
assertRaises(ValueError, f.write, "")
42+
assertRaises(ValueError, f.flush)
3943

4044
# closing a closed file should not throw an error
41-
f.close()
45+
assertf.close()==None
4246

4347
doc="finished"

‎pytest/pytest.go‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"testing"
1313

1414
_ "github.com/go-python/gpython/builtin"
15-
_ "github.com/go-python/gpython/sys"
1615
"github.com/go-python/gpython/compile"
1716
"github.com/go-python/gpython/py"
1817
_ "github.com/go-python/gpython/sys"

0 commit comments

Comments
(0)