Python paramiko: redirecting stderr is affected by get_pty = True
<p>I am trying to implement an ssh agent that will allow me later, among other things, to execute commands in blocking mode, where output is being read from the channel as soon as it is available.<br>
Here's what I have so far:  </p>

<pre><code>from paramiko import client

class SSH_Agent:

    def __init__(self, server_name, username = getpass.getuser(), password = None, connection_timeout = CONNECTION_TIMEOUT):
        self.ssh_agent = client.SSHClient()
        self.ssh_agent.set_missing_host_key_policy(client.AutoAddPolicy())
        self.ssh_agent.connect(server_name, username = username, password = password if password is not None else username, timeout = connection_timeout)


    def execute_command(self, command, out_streams = [sys.stdout], err_streams = [sys.stderr], poll_intervals = POLL_INTERVALS):
        stdin, stdout, stderr = self.ssh_agent.exec_command(command)
        channel = stdout.channel
        stdin.close()
        channel.shutdown_write()

        while not channel.closed or channel.recv_ready() or channel.recv_stderr_ready():
            got_data = False
            output_channels = select.select([channel], [], [], poll_intervals)[0]

            if output_channels:
                channel = output_channels[0]
                if channel.recv_ready():
                    for stream in out_streams:
                        stream.write(channel.recv(len(channel.in_buffer)))
                        stream.flush()
                    got_data = True

                if channel.recv_stderr_ready():
                    for stream in err_streams:
                        stream.write(channel.recv_stderr(len(channel.in_stderr_buffer)))
                        stream.flush()
                    got_data = True

            if not got_data \
            and channel.exit_status_ready() \
            and not channel.recv_ready() \
            and not channel.recv_stderr_ready():
                channel.shutdown_read()
                channel.close()
                break

        return channel.recv_exit_status()
</code></pre>

<p>(this implementation is based on one I found somewhere here in SO)<br>
When I test it, it works fine, except that I get this when executing commands:  </p>

<pre><code>tput: No value for $TERM and no -T specified
</code></pre>

<p>I read a bit online, and found out that happens because there's no actual terminal behind the <code>ssh</code> session.<br>
So, I tried to call <code>paramiko</code>'s <code>exec_command()</code> with <code>get_pty = True</code>:  </p>

<pre><code>stdin, stdout, stderr = self.ssh_agent.exec_command(command, get_pty = True)
</code></pre>

<p>But then I found out that I'm losing the ability to get data to <code>stderr</code> on the channel (everything goes to <code>stdout</code> for some reason, i.e. <code>channel.recv_stderr_ready()</code> is never <code>True</code>). Indeed, I found in the doc the following:  </p>

<blockquote>
  <p>recv_stderr_ready()</p>
  
  <p>Returns true if data is buffered and ready to be read from this channelâs stderr stream. <strong>Only channels using exec_command or
  invoke_shell without a pty will ever have data on the stderr stream</strong>.<br>
      Returns:  True if a recv_stderr call on this channel would immediately return at least one byte; False otherwise.</p>
</blockquote>

<p>How can I have both?<br>
In other words, how can I get rid of this:  </p>

<pre><code>tput: No value for $TERM and no -T specified
</code></pre>

<p>while still having the ability to direct <code>stderr</code> to wherever I choose?</p>

<p><strong>EDIT</strong>:<br>
I Just had an idea...<br>
Can I somehow define this <code>TERM</code> variable in the remote shell to get rid of that error? Is this a common approach or is it a bad workaround that only hides the problem?</p>

<p>Assuming you're running on a *nix system, you could try setting <code>TERM</code> in your command environment instead of creating a pty.</p>

<p>For example:</p>

<pre><code>def execute_command(self, command, out_streams = [sys.stdout], err_streams = [sys.stderr], poll_intervals = POLL_INTERVALS):
    # Pre-pend required environment here
    command = "TERM=xterm " + command
    stdin, stdout, stderr = self.ssh_agent.exec_command(command)
    channel = stdout.channel
    stdin.close()
    channel.shutdown_write()
    ...
</code></pre>

<p>This should still allow you access to the separate streams using your existing code.</p>

python ssh paramiko stderr io-redirection