From f587a9ce6813eeda40563863f89520ce42c429bf Mon Sep 17 00:00:00 2001 From: loulawrence <72574166+loulawrence@users.noreply.github.com> Date: Thu, 1 Apr 2021 15:34:56 -0400 Subject: use pytest stdout/err capture (#22584) * On windows, write to StringIO without redirection in test cases to avoid conflicting with logger --- lib/spack/llnl/util/tty/__init__.py | 2 +- lib/spack/llnl/util/tty/log.py | 93 ++++++++++++++++++++----------------- lib/spack/llnl/util/tty/pty.py | 8 +++- 3 files changed, 59 insertions(+), 44 deletions(-) (limited to 'lib') diff --git a/lib/spack/llnl/util/tty/__init__.py b/lib/spack/llnl/util/tty/__init__.py index ad586e024d..b244b8a58d 100644 --- a/lib/spack/llnl/util/tty/__init__.py +++ b/lib/spack/llnl/util/tty/__init__.py @@ -12,11 +12,11 @@ import sys import textwrap import traceback from datetime import datetime +from sys import platform as _platform import six from six import StringIO from six.moves import input -from sys import platform as _platform if _platform != "win32": import fcntl diff --git a/lib/spack/llnl/util/tty/log.py b/lib/spack/llnl/util/tty/log.py index e86724942a..2551a751f4 100644 --- a/lib/spack/llnl/util/tty/log.py +++ b/lib/spack/llnl/util/tty/log.py @@ -8,20 +8,19 @@ from __future__ import unicode_literals import atexit +import ctypes import errno +import io import multiprocessing import os import re -import io import select import signal import sys -import ctypes -import traceback -import tempfile import threading -from threading import Thread +import traceback from contextlib import contextmanager +from threading import Thread from types import ModuleType # novm from typing import Optional # novm @@ -757,6 +756,9 @@ class winlog: self.stdout = StreamWrapper('stdout') self.stderr = StreamWrapper('stderr') self._active = False + self._ioflag = False + self.old_stdout = sys.stdout + self.old_stderr = sys.stderr def __enter__(self): if self._active: @@ -768,51 +770,59 @@ class winlog: # Open both write and reading on logfile if type(self.logfile) == StringIO: + self._ioflag = True # cannot have two streams on tempfile, so we must make our own - self.writer = open('temp.txt', mode='wb+') - self.reader = open('temp.txt', mode='rb+') + sys.stdout = self.logfile + sys.stderr = self.logfile else: self.writer = open(self.logfile, mode='wb+') self.reader = open(self.logfile, mode='rb+') - # Dup stdout so we can still write to it after redirection - self.echo_writer = open(os.dup(sys.stdout.fileno()), "w") - # Redirect stdout and stderr to write to logfile - self.stderr.redirect_stream(self.writer.fileno()) - self.stdout.redirect_stream(self.writer.fileno()) - self._kill = threading.Event() - - def background_reader(reader, echo_writer, _kill): - # for each line printed to logfile, read it - # if echo: write line to user - while True: - is_killed = _kill.wait(.1) - self.stderr.flush() - self.stdout.flush() - line = reader.readline() - while line: - if self.echo: - self.echo_writer.write('{0}'.format(line.decode())) - self.echo_writer.flush() + + # Dup stdout so we can still write to it after redirection + self.echo_writer = open(os.dup(sys.stdout.fileno()), "w") + # Redirect stdout and stderr to write to logfile + self.stderr.redirect_stream(self.writer.fileno()) + self.stdout.redirect_stream(self.writer.fileno()) + self._kill = threading.Event() + + def background_reader(reader, echo_writer, _kill): + # for each line printed to logfile, read it + # if echo: write line to user + while True: + is_killed = _kill.wait(.1) + self.stderr.flush() + self.stdout.flush() line = reader.readline() + while line: + if self.echo: + self.echo_writer.write('{0}'.format(line.decode())) + self.echo_writer.flush() + line = reader.readline() - if is_killed: - break + if is_killed: + break - self._active = True - with replace_environment(self.env): - self._thread = Thread(target=background_reader, args=(self.reader, self.echo_writer, self._kill)) - self._thread.start() + self._active = True + with replace_environment(self.env): + self._thread = Thread(target=background_reader, + args=(self.reader, self.echo_writer, self._kill)) + self._thread.start() def __exit__(self, exc_type, exc_val, exc_tb): - self.echo_writer.flush() - self.stdout.flush() - self.stderr.flush() - self._kill.set() - self._thread.join() - self.stdout.close() - self.stderr.close() - if os.path.exists("temp.txt"): - os.remove("temp.txt") + if self._ioflag: + sys.stdout = self.old_stdout + sys.stderr = self.old_stderr + self._ioflag = False + else: + self.writer.close() + self.reader.close() + self.echo_writer.flush() + self.stdout.flush() + self.stderr.flush() + self._kill.set() + self._thread.join() + self.stdout.close() + self.stderr.close() self._active = False @contextmanager @@ -835,7 +845,6 @@ class winlog: sys.stdout.flush() - def _writer_daemon(stdin_multiprocess_fd, read_multiprocess_fd, write_fd, echo, log_file_wrapper, control_pipe, filter_fn): """Daemon used by ``log_output`` to write to a log file and to ``stdout``. diff --git a/lib/spack/llnl/util/tty/pty.py b/lib/spack/llnl/util/tty/pty.py index 7ebaa68e42..0475667825 100644 --- a/lib/spack/llnl/util/tty/pty.py +++ b/lib/spack/llnl/util/tty/pty.py @@ -19,7 +19,6 @@ import os import re import signal import sys -import termios import time import traceback @@ -27,6 +26,13 @@ import llnl.util.tty.log as log from spack.util.executable import which +termios = None +try: + import termios as term_mod + termios = term_mod +except ImportError: + pass + class ProcessController(object): """Wrapper around some fundamental process control operations. -- cgit v1.2.3-60-g2f50