Skip to content

Commit d8a60c1

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

File tree

5 files changed

+88
-12
lines changed

5 files changed

+88
-12
lines changed

builtin/builtin.go

+29-5
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

+36-3
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,42 @@ 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+
#if e.args[0] != "'int' object has no attribute 'write'":
171+
# raise
172+
ok = True
173+
assert ok, "AttributeError not raised"
174+
175+
with open("testfile", "w") as f:
176+
print("hello", "world", sep=" ", end="\n", file=f)
177+
178+
with open("testfile", "r") as f:
179+
assert f.read() == "hello world\n"
180+
181+
with open("testfile", "w") as f:
182+
print(1,2,3,sep=",",end=",\n", file=f)
183+
184+
with open("testfile", "r") as f:
185+
assert f.read() == "1,2,3,\n"
153186

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

py/file.go

+21-1
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,20 @@ 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__enter__() (Object, error) {
150+
return o, nil
151+
}
152+
153+
func (o *File) M__exit__(exc_type, exc_value, traceback Object) (Object, error) {
154+
o.Close()
155+
return None, nil
156+
}
157+
141158
func OpenFile(filename, mode string, buffering int) (Object, error) {
142159
var fileMode FileMode
143160
var truncate bool
@@ -177,8 +194,8 @@ func OpenFile(filename, mode string, buffering int) (Object, error) {
177194
return nil, ExceptionNewf(ValueError, "Must have exactly one of create/read/write/append mode and at most one plus")
178195
}
179196

197+
truncate = (fileMode & FileWrite) != 0
180198
fileMode |= FileReadWrite
181-
truncate = false
182199

183200
case 'b':
184201
if fileMode&FileReadWrite == 0 {
@@ -250,3 +267,6 @@ func OpenFile(filename, mode string, buffering int) (Object, error) {
250267
}
251268

252269
// Check interface is satisfied
270+
var _ I__enter__ = (*File)(nil)
271+
var _ I__exit__ = (*File)(nil)
272+
var _ I__exit__ = (*File)(nil)

py/tests/file.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@
3535
assert n == 5
3636

3737
doc = "close"
38-
f.close()
38+
assert f.close() == None
3939

4040
# closing a closed file should not throw an error
41-
f.close()
41+
assert f.close() == None
4242

4343
doc = "finished"

pytest/pytest.go

-1
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)