# Buggy code
def run_command(
    self,
    command,
    sudo=False,
    user=None,
    stop_on_errors=True,
    use_pty=False,
    host_args=None,
    shell=None,
    encoding="utf-8",
    timeout=None,
    greenlet_timeout=None,
):
    """Run command on all hosts in parallel, honoring self.pool_size,
    and return output dictionary.

    This function will block until all commands have been received
    by remote servers and then return immediately.

    More explicitly, function will return after connection and
    authentication establishment and after commands have been accepted by
    successfully established SSH channels.

    Any connection and/or authentication exceptions will be raised here
    and need catching *unless* ``run_command`` is called with
    ``stop_on_errors=False`` in which case exceptions are added to
    individual host output instead.

    :param command: Command to run
    :type command: str
    :param sudo: (Optional) Run with sudo. Defaults to False
    :type sudo: bool
    :param user: (Optional) User to run command as. Requires sudo access
      for that user from the logged in user account.
    :type user: str
    :param stop_on_errors: (Optional) Raise exception on errors running
      command. Defaults to True. With stop_on_errors set to False,
      exceptions are instead added to output of `run_command`. See example
      usage below.
    :type stop_on_errors: bool
    :param shell: (Optional) Override shell to use to run command with.
      Defaults to login user's defined shell. Use the shell's command
      syntax, eg `shell='bash -c'` or `shell='zsh -c'`.
    :type shell: str
    :param use_pty: (Optional) Enable/Disable use of pseudo terminal
      emulation. Disabling it will prohibit capturing standard input/output.
      This is required in majority of cases, exceptions being where a shell
      is not used and/or input/output is not required. In particular
      when running a command which deliberately closes input/output pipes,
      such as a daemon process, you may want to disable ``use_pty``.
      Defaults to ``True``
    :type use_pty: bool
    :param host_args: (Optional) Format command string with per-host
      arguments in ``host_args``. ``host_args`` length must equal length of
      host list - :py:class:`pssh.exceptions.HostArgumentException` is
      raised otherwise
    :type host_args: tuple or list
    :param encoding: Encoding to use for output. Must be valid
      `Python codec <https://docs.python.org/library/codecs.html>`_
    :type encoding: str
    :param timeout: (Optional) Timeout in seconds for reading from stdout
      or stderr. Defaults to no timeout. Reading from stdout/stderr will
      raise :py:class:`pssh.exceptions.Timeout`
      after ``timeout`` number seconds if remote output is not ready.
    :type timeout: int
    :param greenlet_timeout: (Optional) Greenlet timeout setting.
      Defaults to no timeout. If set, this function will raise
      :py:class:`gevent.Timeout` after ``greenlet_timeout`` seconds
      if no result is available from greenlets.
      In some cases, such as when using proxy hosts, connection timeout
      is controlled by proxy server and getting result from greenlets may
      hang indefinitely if remote server is unavailable. Use this setting
      to avoid blocking in such circumstances.
      Note that ``gevent.Timeout`` is a special class that inherits from
      ``BaseException`` and thus **can not be caught** by
      ``stop_on_errors=False``.
    :type greenlet_timeout: float
    :rtype: Dictionary with host as key and
      :py:class:`pssh.output.HostOutput` as value as per
      :py:func:`pssh.pssh_client.ParallelSSHClient.get_output`

    :raises: :py:class:`pssh.exceptions.AuthenticationException` on
      authentication error
    :raises: :py:class:`pssh.exceptions.UnknownHostException` on DNS
      resolution error
    :raises: :py:class:`pssh.exceptions.ConnectionErrorException` on error
      connecting
    :raises: :py:class:`pssh.exceptions.HostArgumentException` on number of
      host arguments not equal to number of hosts
    :raises: :py:class:`TypeError` on not enough host arguments for cmd
      string format
    :raises: :py:class:`KeyError` on no host argument key in arguments
      dict for cmd string format
    :raises: :py:class:`pssh.exceptions.ProxyError` on errors connecting
      to proxy if a proxy host has been set.
    :raises: :py:class:`gevent.Timeout` on greenlet timeout. Gevent timeout
      can not be caught by ``stop_on_errors=False``.
    :raises: Exceptions from :py:mod:`ssh2.exceptions` for all other
      specific errors such as
      :py:class:`ssh2.exceptions.SocketDisconnectError` et al.
    """
    return BaseParallelSSHClient.run_command(
        self,
        command,
        stop_on_errors=stop_on_errors,
        host_args=host_args,
        user=user,
        shell=shell,
        sudo=sudo,
        encoding=encoding,
        use_pty=use_pty,
        timeout=timeout,
        greenlet_timeout=greenlet_timeout,
    )


# Traceback (ValueError)
Traceback (most recent call last):
File "./aws-instances", line 172, in <module>
main()
File "./aws-instances", line 73, in main
facts = remote_facts(ips)
File "./aws-instances", line 146, in remote_facts
out_kern = client.run_command('uname -r')
File "/home/user/do-aws-ec2-facts/aws/lib64/python3.6/site-packages/pssh/clients/native/parallel.py", line 223, in run_command
greenlet_timeout=greenlet_timeout)
File "/home/user/do-aws-ec2-facts/aws/lib64/python3.6/site-packages/pssh/clients/base_pssh.py", line 96, in run_command
self.get_output(cmd, output, timeout=greenlet_timeout)
File "/home/user/do-aws-ec2-facts/aws/lib64/python3.6/site-packages/pssh/clients/base_pssh.py", line 141, in get_output
(channel, host, stdout, stderr, stdin) = cmd.get(timeout=timeout)
File "src/gevent/greenlet.py", line 709, in gevent._greenlet.Greenlet.get
File "src/gevent/greenlet.py", line 317, in gevent._greenlet.Greenlet._raise_exception
File "/home/user/do-aws-ec2-facts/aws/lib64/python3.6/site-packages/gevent/_compat.py", line 47, in reraise
raise value.with_traceback(tb)
File "src/gevent/greenlet.py", line 766, in gevent._greenlet.Greenlet.run
File "/home/user/do-aws-ec2-facts/aws/lib64/python3.6/site-packages/pssh/clients/native/parallel.py", line 237, in _run_command
raise ex
File "/home/user/do-aws-ec2-facts/aws/lib64/python3.6/site-packages/pssh/clients/native/parallel.py", line 233, in _run_command
use_pty=use_pty, encoding=encoding, timeout=timeout)
File "/home/user/do-aws-ec2-facts/aws/lib64/python3.6/site-packages/pssh/clients/native/single.py", line 442, in run_command
channel = self.execute(_command, use_pty=use_pty)
File "/home/user/do-aws-ec2-facts/aws/lib64/python3.6/site-packages/pssh/clients/native/single.py", line 324, in execute
channel = self.open_session() if channel is None else channel
File "/home/user/do-aws-ec2-facts/aws/lib64/python3.6/site-packages/pssh/clients/native/single.py", line 297, in open_session
wait_select(self.session)
File "pssh/native/_ssh2.pyx", line 171, in pssh.native._ssh2.wait_select
File "/home/user/do-aws-ec2-facts/aws/lib64/python3.6/site-packages/gevent/select.py", line 145, in select
sel_results = _original_select(rlist, wlist, xlist, 0)
ValueError: filedescriptor out of range in select()

# Fixed code
def run_command(
    self,
    command,
    sudo=False,
    user=None,
    stop_on_errors=True,
    use_pty=False,
    host_args=None,
    shell=None,
    encoding="utf-8",
    timeout=None,
    greenlet_timeout=None,
    return_list=False,
):
    """Run command on all hosts in parallel, honoring self.pool_size,
    and return output dictionary.

    This function will block until all commands have been received
    by remote servers and then return immediately.

    More explicitly, function will return after connection and
    authentication establishment and after commands have been accepted by
    successfully established SSH channels.

    Any connection and/or authentication exceptions will be raised here
    and need catching *unless* ``run_command`` is called with
    ``stop_on_errors=False`` in which case exceptions are added to
    individual host output instead.

    :param command: Command to run
    :type command: str
    :param sudo: (Optional) Run with sudo. Defaults to False
    :type sudo: bool
    :param user: (Optional) User to run command as. Requires sudo access
      for that user from the logged in user account.
    :type user: str
    :param stop_on_errors: (Optional) Raise exception on errors running
      command. Defaults to True. With stop_on_errors set to False,
      exceptions are instead added to output of `run_command`. See example
      usage below.
    :type stop_on_errors: bool
    :param shell: (Optional) Override shell to use to run command with.
      Defaults to login user's defined shell. Use the shell's command
      syntax, eg `shell='bash -c'` or `shell='zsh -c'`.
    :type shell: str
    :param use_pty: (Optional) Enable/Disable use of pseudo terminal
      emulation. Disabling it will prohibit capturing standard input/output.
      This is required in majority of cases, exceptions being where a shell
      is not used and/or input/output is not required. In particular
      when running a command which deliberately closes input/output pipes,
      such as a daemon process, you may want to disable ``use_pty``.
      Defaults to ``True``
    :type use_pty: bool
    :param host_args: (Optional) Format command string with per-host
      arguments in ``host_args``. ``host_args`` length must equal length of
      host list - :py:class:`pssh.exceptions.HostArgumentException` is
      raised otherwise
    :type host_args: tuple or list
    :param encoding: Encoding to use for output. Must be valid
      `Python codec <https://docs.python.org/library/codecs.html>`_
    :type encoding: str
    :param timeout: (Optional) Timeout in seconds for reading from stdout
      or stderr. Defaults to no timeout. Reading from stdout/stderr will
      raise :py:class:`pssh.exceptions.Timeout`
      after ``timeout`` number seconds if remote output is not ready.
    :type timeout: int
    :param greenlet_timeout: (Optional) Greenlet timeout setting.
      Defaults to no timeout. If set, this function will raise
      :py:class:`gevent.Timeout` after ``greenlet_timeout`` seconds
      if no result is available from greenlets.
      In some cases, such as when using proxy hosts, connection timeout
      is controlled by proxy server and getting result from greenlets may
      hang indefinitely if remote server is unavailable. Use this setting
      to avoid blocking in such circumstances.
      Note that ``gevent.Timeout`` is a special class that inherits from
      ``BaseException`` and thus **can not be caught** by
      ``stop_on_errors=False``.
    :type greenlet_timeout: float
    :param return_list: (Optional) Return a list of ``HostOutput`` objects
      instead of dictionary. ``run_command`` will return a list starting
      from 2.0.0 - enable this flag to avoid client code breaking on
      upgrading to 2.0.0.
    :type return_list: bool
    :rtype: Dictionary with host as key and
      :py:class:`pssh.output.HostOutput` as value
      *or* list(:py:class:`pssh.output.HostOutput`) when
      ``return_list=True``
    :raises: :py:class:`pssh.exceptions.AuthenticationException` on
      authentication error
    :raises: :py:class:`pssh.exceptions.UnknownHostException` on DNS
      resolution error
    :raises: :py:class:`pssh.exceptions.ConnectionErrorException` on error
      connecting
    :raises: :py:class:`pssh.exceptions.HostArgumentException` on number of
      host arguments not equal to number of hosts
    :raises: :py:class:`TypeError` on not enough host arguments for cmd
      string format
    :raises: :py:class:`KeyError` on no host argument key in arguments
      dict for cmd string format
    :raises: :py:class:`pssh.exceptions.ProxyError` on errors connecting
      to proxy if a proxy host has been set.
    :raises: :py:class:`gevent.Timeout` on greenlet timeout. Gevent timeout
      can not be caught by ``stop_on_errors=False``.
    :raises: Exceptions from :py:mod:`ssh2.exceptions` for all other
      specific errors such as
      :py:class:`ssh2.exceptions.SocketDisconnectError` et al.
    """
    return BaseParallelSSHClient.run_command(
        self,
        command,
        stop_on_errors=stop_on_errors,
        host_args=host_args,
        user=user,
        shell=shell,
        sudo=sudo,
        encoding=encoding,
        use_pty=use_pty,
        timeout=timeout,
        greenlet_timeout=greenlet_timeout,
        return_list=return_list,
    )