Python paramiko: redirecting stderr is affected by get_pty = True
Question: 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.  
Here's what I have so far:

    
    
    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()
    

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

    
    
    tput: No value for $TERM and no -T specified
    

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

    
    
    stdin, stdout, stderr = self.ssh_agent.exec_command(command, get_pty = True)
    

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

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

How can I have both?  
In other words, how can I get rid of this:

    
    
    tput: No value for $TERM and no -T specified
    

while still having the ability to direct `stderr` to wherever I choose?

**EDIT** :  
I Just had an idea...  
Can I somehow define this `TERM` 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?


Answer: Assuming you're running on a *nix system, you could try setting `TERM` in your
command environment instead of creating a pty.

For example:

    
    
    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()
        ...
    

This should still allow you access to the separate streams using your existing
code.

