IronLanguages / ironpython3

Implementation of Python 3.x for .NET Framework that is built on top of the Dynamic Language Runtime.
Apache License 2.0
2.47k stars 288 forks source link

FileIO, BufferedWriter left unflushed when ipy exits #938

Open jameslan opened 4 years ago

jameslan commented 4 years ago
import io
out = io.FileIO('test.txt', 'w')
out.write(b'a')
import io
out = io.TextIOWrapper(io.BufferedWriter(io.FileIO('test.txt', 'w')))
out.write('a')

The following powershell command output nothing,

PS C:\Users\james\proj\ironpython3> .\bin\Debug\netcoreapp3.1\ipy.exe -c "import sys;sys.stdout.write('text')"
PS C:\Users\james\proj\ironpython3>

and the following powershell command could output the "text"

PS C:\Users\james\proj\ironpython3> .\bin\Debug\netcoreapp3.1\ipy.exe -c "import sys;sys.stdout.write('text\n')"
text
PS C:\Users\james\proj\ironpython3>
slozier commented 4 years ago

For the TextIOWrapper it seems like flush is called by __del__:

import io
class Test(io.TextIOWrapper):
    def __del__(self):
        pass
out = Test(io.BufferedWriter(io.FileIO('test.txt', 'w')))
out.write('a')

Probably similar for io.FileIO. For writing to standard streams it looks like CPython calls flush on sys.stdout and sys.stderr during Py_FinalizeEx. See https://github.com/python/cpython/blob/6c065594c720fdd4783a4284cb9f2eebcb2c10bd/Python/pylifecycle.c#L480-L502

jameslan commented 4 years ago

sys.stdout is TextIOWrapper(BufferedWriter(FileIO(Console.OpenStandardOutput()))) and sys.stderr is TextIOWrapper(BufferedWriter(FileIO(Console.OpenStandardError())))

So I think if TextIOWrapper or BufferedWriter could flush at exit, sys.stdout and sys.stderr should be good.

stdio are created here https://github.com/IronLanguages/ironpython3/blob/f32bf73f364c176db5cbbb6cefc6ec5f9fc92934/Src/IronPython/Runtime/PythonContext.cs#L1830-L1834

and https://github.com/IronLanguages/ironpython3/blob/f32bf73f364c176db5cbbb6cefc6ec5f9fc92934/Src/IronPython/Modules/_io.cs#L2847-L2859