Skip to content

Commit fb4a4f2

Browse files
committed
Add support for print to file and file flush.
1 parent ee952c8 commit fb4a4f2

File tree

3 files changed

+85
-9
lines changed

3 files changed

+85
-9
lines changed

builtin/builtin.go

Lines changed: 29 additions & 5 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,44 @@ 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)
189+
190+
write, err := py.GetAttrString(file, "write")
191+
if err != nil {
192+
return nil, err
193+
}
194+
190195
// FIXME ignoring file and flush
191196
for i, v := range args {
192197
v, err := py.Str(v)
193198
if err != nil {
194199
return nil, err
195200
}
196201

197-
fmt.Printf("%v", v)
202+
_, err = py.Call(write, py.Tuple{v}, nil)
203+
if err != nil {
204+
return nil, err
205+
}
206+
198207
if i != len(args)-1 {
199-
fmt.Print(sep)
208+
_, err = py.Call(write, py.Tuple{sep}, nil)
209+
if err != nil {
210+
return nil, err
211+
}
200212
}
201213
}
202-
fmt.Print(end)
214+
215+
_, err = py.Call(write, py.Tuple{end}, nil)
216+
if err != nil {
217+
return nil, err
218+
}
219+
220+
if shouldFlush, _ := py.MakeBool(flush); shouldFlush == py.True {
221+
fflush, err := py.GetAttrString(file, "flush")
222+
if err == nil {
223+
py.Call(fflush, nil, nil)
224+
}
225+
}
226+
203227
return py.None, nil
204228
}
205229

builtin/tests/builtin.py

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,47 @@ def gen2():
147147
assert repr("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+
except TypeError as e:
154+
#if e.args[0] != "sep must be None or a string, not int":
155+
# raise
156+
ok = True
157+
assert ok, "TypeError not raised"
158+
159+
try:
160+
print("hello", sep=" ", end=1)
161+
except TypeError as e:
162+
#if e.args[0] != "end must be None or a string, not int":
163+
# raise
164+
ok = True
165+
assert ok, "TypeError not raised"
166+
167+
try:
168+
print("hello", sep=" ", end="\n", file=1)
169+
except AttributeError as e:
170+
print(e.args[0])
171+
#if e.args[0] != "'int' object has no attribute 'write'":
172+
# raise
173+
ok = True
174+
assert ok, "AttributeError not raised"
175+
176+
f = open("testfile", "w")
177+
print("hello", "world", sep=" ", end="\n", file=f)
178+
assert f.close() is None
179+
180+
f = open("testfile", "r")
181+
assert f.read() == "hello world\n"
182+
assert f.close() is None
183+
184+
f = open("testfile", "w")
185+
print(1,2,3,sep=",",end=",\n", file=f)
186+
assert f.close() is None
187+
188+
f= open("testfile", "r")
189+
assert f.read() == "1,2,3,\n"
190+
assert f.close() is None
153191

154192
doc="round"
155193
assert round(1.1) == 1.0

py/file.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ func init() {
2828
FileType.Dict["close"] = MustNewMethod("close", func(self Object) (Object, error) {
2929
return self.(*File).Close()
3030
}, 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.")
31+
FileType.Dict["flush"] = MustNewMethod("flush", func(self Object) (Object, error) {
32+
return self.(*File).Flush()
33+
}, 0, "flush() -> Flush the write buffers of the stream if applicable. This does nothing for read-only and non-blocking streams.")
3134
}
3235

3336
type FileMode int
@@ -138,6 +141,16 @@ func (o *File) Close() (Object, error) {
138141
return None, nil
139142
}
140143

144+
func (o *File) Flush() (Object, error) {
145+
_ = o.File.Sync()
146+
return None, nil
147+
}
148+
149+
func (o *File) M__exit__(exc_type, exc_value, traceback Object) (Object, error) {
150+
o.Close()
151+
return None, nil
152+
}
153+
141154
func OpenFile(filename, mode string, buffering int) (Object, error) {
142155
var fileMode FileMode
143156
var truncate bool
@@ -177,8 +190,8 @@ func OpenFile(filename, mode string, buffering int) (Object, error) {
177190
return nil, ExceptionNewf(ValueError, "Must have exactly one of create/read/write/append mode and at most one plus")
178191
}
179192

193+
truncate = (fileMode & FileWrite) != 0
180194
fileMode |= FileReadWrite
181-
truncate = false
182195

183196
case 'b':
184197
if fileMode&FileReadWrite == 0 {
@@ -250,3 +263,4 @@ func OpenFile(filename, mode string, buffering int) (Object, error) {
250263
}
251264

252265
// Check interface is satisfied
266+
var _ I__exit__ = (*File)(nil)

0 commit comments

Comments
 (0)