Remove uses of os.dup2() from run_tests.py in order to adapt the new console
reader and writer on Windows since Python 3.6.
* build/run_tests.py
(open_logfile): New function returning file-like object which is reassignable
sys.stdout and sys.stderr.
(TestHarness.run): Use open_logfile() instead of codecs.open().
(TestHarness._open_log): Ditto.
(TestHarness._run_py_test): Reassign sys.stdout and sys.stderr instead of
uses of os.dup2().
* subversion/tests/cmdline/svntest/main.py
(LoggingStdoutHandler): New function to use the value of sys.stdout at call
time.
(parse_options): Use LoggingStdoutHandler() instead of
StreamHandler(sys.stdout).
Tested by: jcorvel
Reviewed by: jcorvel
futatuki
git-svn-id: https://svn.apache.org/repos/asf/subversion/trunk@1883337 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/build/run_tests.py b/build/run_tests.py
index 5a661af..7b4eb15 100755
--- a/build/run_tests.py
+++ b/build/run_tests.py
@@ -47,7 +47,7 @@
separated list of test numbers; the default is to run all the tests in it.
'''
-import os, sys, shutil, codecs
+import os, sys, shutil
import re
import logging
import optparse, subprocess, threading, traceback
@@ -141,6 +141,18 @@
else:
return s.decode("latin-1")
+def open_logfile(filename, mode, encoding='utf-8'):
+ if sys.version_info[0] != 2:
+ return open(filename, mode, encoding=encoding, errors='surrogateescape')
+ else:
+ class Wrapper(object):
+ def __init__(self, stream, encoding):
+ self._stream = stream
+ self.encoding = encoding
+ def __getattr__(self, name):
+ return getattr(self._stream, name)
+ return Wrapper(open(filename, mode), encoding)
+
class TestHarness:
'''Test harness for Subversion tests.
'''
@@ -700,7 +712,7 @@
# Copy the truly interesting verbose logs to a separate file, for easier
# viewing.
if xpassed or failed_list:
- faillog = codecs.open(self.faillogfile, 'w', encoding="latin-1")
+ faillog = open_logfile(self.faillogfile, 'w')
last_start_lineno = None
last_start_re = re.compile('^(FAIL|SKIP|XFAIL|PASS|START|CLEANUP|END):')
for lineno, line in enumerate(log_lines):
@@ -733,7 +745,7 @@
'Open the log file with the required MODE.'
if self.logfile:
self._close_log()
- self.log = codecs.open(self.logfile, mode, encoding="latin-1")
+ self.log = open_logfile(self.logfile, mode)
def _close_log(self):
'Close the log file.'
@@ -843,14 +855,13 @@
sys.exit(1)
# setup the output pipes
+ old_stdout = sys.stdout.fileno()
if self.log:
sys.stdout.flush()
sys.stderr.flush()
self.log.flush()
- old_stdout = os.dup(sys.stdout.fileno())
- old_stderr = os.dup(sys.stderr.fileno())
- os.dup2(self.log.fileno(), sys.stdout.fileno())
- os.dup2(self.log.fileno(), sys.stderr.fileno())
+ saved_stds = sys.stdout, sys.stderr
+ sys.stdout = sys.stderr = self.log
# These have to be class-scoped for use in the progress_func()
self.dots_written = 0
@@ -891,12 +902,8 @@
# restore some values
if self.log:
- sys.stdout.flush()
- sys.stderr.flush()
- os.dup2(old_stdout, sys.stdout.fileno())
- os.dup2(old_stderr, sys.stderr.fileno())
- os.close(old_stdout)
- os.close(old_stderr)
+ self.log.flush()
+ sys.stdout, sys.stderr = saved_stds
return failed
diff --git a/subversion/tests/cmdline/svntest/main.py b/subversion/tests/cmdline/svntest/main.py
index af82ecc..fe54d38 100644
--- a/subversion/tests/cmdline/svntest/main.py
+++ b/subversion/tests/cmdline/svntest/main.py
@@ -2080,6 +2080,23 @@
record.levelshort = self._level_short[record.levelno]
return logging.Formatter.format(self, record)
+
+class LoggingStdoutHandler(logging.StreamHandler):
+ """
+ The handler is always writing using sys.stdout at call time rather than the
+ value of sys.stdout at construction time.
+
+ Inspired by logging._StderrHandler on Python 3.
+ """
+
+ def __init__(self, level=logging.NOTSET):
+ logging.Handler.__init__(self, level)
+
+ @property
+ def stream(self):
+ return sys.stdout
+
+
def _create_parser(usage=None):
"""Return a parser for our test suite."""
@@ -2272,7 +2289,7 @@
datefmt='%Y-%m-%d %H:%M:%S')
else:
formatter = AbbreviatedFormatter('%(levelshort)s: %(message)s')
- handler = logging.StreamHandler(sys.stdout)
+ handler = LoggingStdoutHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)