On 2020/04/21 4:03, Johan Corveleyn wrote:
> On Mon, Apr 20, 2020 at 2:16 PM Yasuhito FUTATSUKI <futat...@poem.co.jp>

<snip>

>> So I wrote a patch for testing (not for commit. it is need to brush up
>> even if it can work).
>>
>> At least it should work (no regression) on Python 2.7, Python 3 with
>> and without PYTHONLEGACYWINDOWSSTDIO on Windows.
>>
>> (I confirmed on Python 2.7 and Python 3.7 on FreeBSD).
>>
>> Thanks,
>> --
>> Yasuhito FUTATSUKI <futat...@poem.co.jp>
>>
> 
> Perfect! Works well on Windows, with Py 2.7, 3.7 and 3.8.2, with or without
> the envvar defined.
> Thanks!

Thank you!

Then I update the patch to prepare to commit. However I don't have
confidence function name, variable names, and comment, etc.

Could anyone please refine it?  

Thanks,
-- 
Yasuhito FUTATSUKI <futat...@yf.bsdclub.org>/<futat...@poem.co.jp>
Fix an issue on run tests on Windows with Python 3.6 and later.

Since Python 3.6 on Windows, io.IOBase object overlaid tty is incompatible
with which of other file like objects. It makes impossible to redirect
input or output between file and tty without changing file descriptor number
by using os.dup2() without changing overlaid object[1]. This is a work
around for it.

[1] _io._WindowsConsoleIO breaks in the face of fd redirection
   https://bugs.python.org/issue30555

* build/run_tests.py
 (rebuild_textio): New.
 (TestHarness._run_py_test): Rebuild IO object after os.dup2() if it is needed.

Reported by: jcorvel

Index: build/run_tests.py
===================================================================
--- build/run_tests.py  (revision 1876712)
+++ build/run_tests.py  (working copy)
@@ -48,6 +48,7 @@
 '''
 
 import os, sys, shutil, codecs
+import io
 import re
 import logging
 import optparse, subprocess, threading, traceback
@@ -141,6 +142,10 @@
   else:
     return s.decode("latin-1")
 
+def rebuild_textio(fd, mode):
+  '''Rebuild an io.BaseIO object from file descriptor for sys.std*'''
+  return open(fd, mode, encoding='utf-8', errors='replace', closefd=False)
+
 class TestHarness:
   '''Test harness for Subversion tests.
   '''
@@ -844,6 +849,16 @@
 
     # setup the output pipes
     if self.log:
+      # Since Python 3.6 on Windows, redirecting tty to file or file to tty
+      # by using os.dup2 breaks overlaid IO object.
+      # (See https://bugs.python.org/issue30555).
+      # To avoid this, we rebuild IO object after os.dup2 if it is needed.
+      need_rebuild_stdout = (    isinstance(sys.stdout, io.IOBase)
+                             and not isinstance(sys.stdout.buffer.raw,
+                                                io.FileIO))
+      need_rebuild_stderr = (    isinstance(sys.stderr, io.IOBase)
+                             and not isinstance(sys.stderr.buffer.raw,
+                                                io.FileIO))
       sys.stdout.flush()
       sys.stderr.flush()
       self.log.flush()
@@ -851,6 +866,10 @@
       old_stderr = os.dup(sys.stderr.fileno())
       os.dup2(self.log.fileno(), sys.stdout.fileno())
       os.dup2(self.log.fileno(), sys.stderr.fileno())
+      if need_rebuild_stdout:
+        sys.stdout = rebuild_textio(sys.stdout.fileno(), 'w')
+      if need_rebuild_stderr:
+        sys.stderr = rebuild_textio(sys.stderr.fileno(), 'w')
 
     # These have to be class-scoped for use in the progress_func()
     self.dots_written = 0
@@ -897,6 +916,10 @@
       os.dup2(old_stderr, sys.stderr.fileno())
       os.close(old_stdout)
       os.close(old_stderr)
+      if need_rebuild_stdout:
+        sys.stdout = rebuild_textio(sys.stdout.fileno(), 'w')
+      if need_rebuild_stderr:
+        sys.stderr = rebuild_textio(sys.stderr.fileno(), 'w')
 
     return failed
 

Reply via email to