# Buggy code
def _writer_daemon(self, stdin):
    """Daemon that writes output to the log file and stdout."""
    # Use line buffering (3rd param = 1) since Python 3 has a bug
    # that prevents unbuffered text I/O.
    in_pipe = os.fdopen(self.read_fd, "r", 1)
    os.close(self.write_fd)

    echo = self.echo  # initial echo setting, user-controllable
    force_echo = False  # parent can force echo for certain output

    # list of streams to select from
    istreams = [in_pipe, stdin] if stdin else [in_pipe]

    log_file = self.log_file

    def handle_write(force_echo):
        # Handle output from the with block process.
        # If we arrive here it means that in_pipe was
        # ready for reading : it should never happen that
        # line is false-ish
        line = in_pipe.readline()
        if not line:
            return (True, force_echo)  # break while loop

        # find control characters and strip them.
        controls = control.findall(line)
        line = re.sub(control, "", line)

        # Echo to stdout if requested or forced
        if echo or force_echo:
            try:
                if termios:
                    conf = termios.tcgetattr(sys.stdout)
                    tostop = conf[3] & termios.TOSTOP
                else:
                    tostop = True
            except Exception:
                tostop = True
            if not (tostop and _is_background_tty()):
                sys.stdout.write(line)
                sys.stdout.flush()

        # Stripped output to log file.
        log_file.write(_strip(line))
        log_file.flush()

        if xon in controls:
            force_echo = True
        if xoff in controls:
            force_echo = False
        return (False, force_echo)

    try:
        with _keyboard_input(stdin):
            while True:
                # No need to set any timeout for select.select
                # Wait until a key press or an event on in_pipe.
                rlist, _, _ = select.select(istreams, [], [])
                # Allow user to toggle echo with 'v' key.
                # Currently ignores other chars.
                # only read stdin if we're in the foreground
                if stdin in rlist and not _is_background_tty():
                    if stdin.read(1) == "v":
                        echo = not echo

                if in_pipe in rlist:
                    br, fe = handle_write(force_echo)
                    force_echo = fe
                    if br:
                        break

    except BaseException:
        tty.error("Exception occurred in writer daemon!")
        traceback.print_exc()

    finally:
        # send written data back to parent if we used a StringIO
        if self.write_log_in_parent:
            self.child.send(log_file.getvalue())
        log_file.close()

    # send echo value back to the parent so it can be preserved.
    self.child.send(echo)


# Traceback (KeyError)
Traceback (most recent call last):
File "/u/sciteam/stewart1/spack/bin/spack", line 64, in <module>
sys.exit(spack.main.main())
File "/mnt/a/u/sciteam/stewart1/spack/lib/spack/spack/main.py", line 770, in main
if spack.config.get('config:debug'):
File "/mnt/a/u/sciteam/stewart1/spack/lib/spack/spack/config.py", line 671, in get
return config.get(path, default, scope)
File "/mnt/a/u/sciteam/stewart1/spack/lib/spack/llnl/util/lang.py", line 552, in __getattr__
return getattr(self.instance, name)
File "/mnt/a/u/sciteam/stewart1/spack/lib/spack/llnl/util/lang.py", line 548, in instance
self._instance = self.factory()
File "/mnt/a/u/sciteam/stewart1/spack/lib/spack/spack/config.py", line 653, in _config
_add_platform_scope(cfg, ConfigScope, name, path)
File "/mnt/a/u/sciteam/stewart1/spack/lib/spack/spack/config.py", line 606, in _add_platform_scope
platform = spack.architecture.platform().name
File "/mnt/a/u/sciteam/stewart1/spack/lib/spack/llnl/util/lang.py", line 178, in _memoized_function
func.cache[args] = func(*args)
File "/mnt/a/u/sciteam/stewart1/spack/lib/spack/spack/architecture.py", line 516, in platform
return platform_cls()
File "/mnt/a/u/sciteam/stewart1/spack/lib/spack/spack/platforms/cray.py", line 63, in __init__
_target = self._default_target_from_env()
File "/mnt/a/u/sciteam/stewart1/spack/lib/spack/spack/platforms/cray.py", line 121, in _default_target_from_env
env={'TERM': os.environ['TERM']},
File "/usr/lib64/python2.6/UserDict.py", line 22, in __getitem__
raise KeyError(key)
KeyError: 'TERM'

# Fixed code
def _writer_daemon(stdin, read_fd, write_fd, echo, log_file, control_pipe):
    """Daemon used by ``log_output`` to write to a log file and to ``stdout``.

    The daemon receives output from the parent process and writes it both
    to a log and, optionally, to ``stdout``.  The relationship looks like
    this::

        Terminal
           |
           |          +-------------------------+
           |          | Parent Process          |
           +--------> |   with log_output():    |
           | stdin    |     ...                 |
           |          +-------------------------+
           |            ^             | write_fd (parent's redirected stdout)
           |            | control     |
           |            | pipe        |
           |            |             v read_fd
           |          +-------------------------+   stdout
           |          | Writer daemon           |------------>
           +--------> |   read from read_fd     |   log_file
             stdin    |   write to out and log  |------------>
                      +-------------------------+

    Within the ``log_output`` handler, the parent's output is redirected
    to a pipe from which the daemon reads.  The daemon writes each line
    from the pipe to a log file and (optionally) to ``stdout``.  The user
    can hit ``v`` to toggle output on ``stdout``.

    In addition to the input and output file descriptors, the daemon
    interacts with the parent via ``control_pipe``.  It reports whether
    ``stdout`` was enabled or disabled when it finished and, if the
    ``log_file`` is a ``StringIO`` object, then the daemon also sends the
    logged output back to the parent as a string, to be written to the
    ``StringIO`` in the parent. This is mainly for testing.

    Arguments:
        stdin (stream): input from the terminal
        read_fd (int): pipe for reading from parent's redirected stdout
        write_fd (int): parent's end of the pipe will write to (will be
            immediately closed by the writer daemon)
        echo (bool): initial echo setting -- controlled by user and
            preserved across multiple writer daemons
        log_file (file-like): file to log all output
        control_pipe (Pipe): multiprocessing pipe on which to send control
            information to the parent

    """
    # Use line buffering (3rd param = 1) since Python 3 has a bug
    # that prevents unbuffered text I/O.
    in_pipe = os.fdopen(read_fd, "r", 1)
    os.close(write_fd)

    # list of streams to select from
    istreams = [in_pipe, stdin] if stdin else [in_pipe]
    force_echo = False  # parent can force echo for certain output

    try:
        with keyboard_input(stdin) as kb:
            while True:
                # fix the terminal settings if we recently came to
                # the foreground
                kb.check_fg_bg()

                # wait for input from any stream. use a coarse timeout to
                # allow other checks while we wait for input
                rlist, _, _ = _retry(select.select)(istreams, [], [], 1e-1)

                # Allow user to toggle echo with 'v' key.
                # Currently ignores other chars.
                # only read stdin if we're in the foreground
                if stdin in rlist and not _is_background_tty(stdin):
                    # it's possible to be backgrounded between the above
                    # check and the read, so we ignore SIGTTIN here.
                    with ignore_signal(signal.SIGTTIN):
                        try:
                            if stdin.read(1) == "v":
                                echo = not echo
                        except IOError as e:
                            # If SIGTTIN is ignored, the system gives EIO
                            # to let the caller know the read failed b/c it
                            # was in the bg. Ignore that too.
                            if e.errno != errno.EIO:
                                raise

                if in_pipe in rlist:
                    # Handle output from the calling process.
                    line = _retry(in_pipe.readline)()
                    if not line:
                        break

                    # find control characters and strip them.
                    controls = control.findall(line)
                    line = control.sub("", line)

                    # Echo to stdout if requested or forced.
                    if echo or force_echo:
                        sys.stdout.write(line)
                        sys.stdout.flush()

                    # Stripped output to log file.
                    log_file.write(_strip(line))
                    log_file.flush()

                    if xon in controls:
                        force_echo = True
                    if xoff in controls:
                        force_echo = False

    except BaseException:
        tty.error("Exception occurred in writer daemon!")
        traceback.print_exc()

    finally:
        # send written data back to parent if we used a StringIO
        if isinstance(log_file, StringIO):
            control_pipe.send(log_file.getvalue())
        log_file.close()

    # send echo value back to the parent so it can be preserved.
    control_pipe.send(echo)