class_docstr: This class represents a process running in a pseudoterminal.
  
  The main constructor is the :meth:`spawn` classmethod.
docstr: Start the given command in a child process in a pseudo terminal.
  
  This does all the fork/exec type of stuff for a pty, and returns an
  instance of PtyProcess.
  
  If preexec_fn is supplied, it will be called with no arguments in the
  child process before exec-ing the specified command.
  It may, for instance, set signal handlers to SIG_DFL or SIG_IGN.
  
  Dimensions of the psuedoterminal used for the subprocess can be
  specified as a tuple (rows, cols), or the default (24, 80) will be used.
  
  By default, all file descriptors except 0, 1 and 2 are closed. This
  behavior can be overridden with pass_fds, a list of file descriptors to
  keep open between the parent and the child.
docstr_tok: ["Start","the","given","command","in","a","child","process","in","a","pseudo","terminal",".","This","does","all","the","fork\/exec","type","of","stuff","for","a","pty",",","and","returns","an","instance","of","PtyProcess",".","If","preexec_fn","is","supplied",",","it","will","be","called","with","no","arguments","in","the","child","process","before","exec-ing","the","specified","command",".","It","may",",","for","instance",",","set","signal","handlers","to","SIG_DFL","or","SIG_IGN",".","Dimensions","of","the","psuedoterminal","used","for","the","subprocess","can","be","specified","as","a","tuple","(","rows",",","cols",")",",","or","the","default","(","24",",","80",")","will","be","used",".","By","default",",","all","file","descriptors","except","0",",","1","and","2","are","closed",".","This","behavior","can","be","overridden","with","pass_fds",",","a","list","of","file","descriptors","to","keep","open","between","the","parent","and","the","child","."]
code: def spawn(
      cls,
      argv,
      cwd=None,
      env=None,
      echo=True,
      preexec_fn=None,
      dimensions=(24, 80),
      pass_fds=(),
  ):
      """Start the given command in a child process in a pseudo terminal.
  
      This does all the fork/exec type of stuff for a pty, and returns an
      instance of PtyProcess.
  
      If preexec_fn is supplied, it will be called with no arguments in the
      child process before exec-ing the specified command.
      It may, for instance, set signal handlers to SIG_DFL or SIG_IGN.
  
      Dimensions of the psuedoterminal used for the subprocess can be
      specified as a tuple (rows, cols), or the default (24, 80) will be used.
  
      By default, all file descriptors except 0, 1 and 2 are closed. This
      behavior can be overridden with pass_fds, a list of file descriptors to
      keep open between the parent and the child.
      """
      # Note that it is difficult for this method to fail.
      # You cannot detect if the child process cannot start.
      # So the only way you can tell if the child process started
      # or not is to try to read from the file descriptor. If you get
      # EOF immediately then it means that the child is already dead.
      # That may not necessarily be bad because you may have spawned a child
      # that performs some task; creates no stdout output; and then dies.
  
      if not isinstance(argv, (list, tuple)):
          raise TypeError(
              "Expected a list or tuple for argv, got %r" % argv
          )
  
      # Shallow copy of argv so we can modify it
      argv = argv[:]
      command = argv[0]
  
      command_with_path = which(command)
      if command_with_path is None:
          raise FileNotFoundError(
              "The command was not found or was not "
              + "executable: %s." % command
          )
      command = command_with_path
      argv[0] = command
  
      # [issue #119] To prevent the case where exec fails and the user is
      # stuck interacting with a python child process instead of whatever
      # was expected, we implement the solution from
      # http://stackoverflow.com/a/3703179 to pass the exception to the
      # parent process
  
      # [issue #119] 1. Before forking, open a pipe in the parent process.
      exec_err_pipe_read, exec_err_pipe_write = os.pipe()
  
      if use_native_pty_fork:
          pid, fd = pty.fork()
      else:
          # Use internal fork_pty, for Solaris
          pid, fd = _fork_pty.fork_pty()
  
      # Some platforms must call setwinsize() and setecho() from the
      # child process, and others from the master process. We do both,
      # allowing IOError for either.
  
      if pid == CHILD:
          # set window size
          try:
              _setwinsize(STDIN_FILENO, *dimensions)
          except IOError as err:
              if err.args[0] not in (errno.EINVAL, errno.ENOTTY):
                  raise
  
          # disable echo if spawn argument echo was unset
          if not echo:
              try:
                  _setecho(STDIN_FILENO, False)
              except (IOError, termios.error) as err:
                  if err.args[0] not in (errno.EINVAL, errno.ENOTTY):
                      raise
  
          # [issue #119] 3. The child closes the reading end and sets the
          # close-on-exec flag for the writing end.
          os.close(exec_err_pipe_read)
          fcntl.fcntl(
              exec_err_pipe_write, fcntl.F_SETFD, fcntl.FD_CLOEXEC
          )
  
          # Do not allow child to inherit open file descriptors from parent,
          # with the exception of the exec_err_pipe_write of the pipe
          # and pass_fds.
          # Impose ceiling on max_fd: AIX bugfix for users with unlimited
          # nofiles where resource.RLIMIT_NOFILE is 2^63-1 and os.closerange()
          # occasionally raises out of range error
          max_fd = min(
              1048576, resource.getrlimit(resource.RLIMIT_NOFILE)[0]
          )
          spass_fds = sorted(set(pass_fds) | {exec_err_pipe_write})
          for pair in zip([2] + spass_fds, spass_fds + [max_fd]):
              os.closerange(pair[0] + 1, pair[1])
  
          if cwd is not None:
              os.chdir(cwd)
  
          if preexec_fn is not None:
              try:
                  preexec_fn()
              except Exception as e:
                  ename = type(e).__name__
                  tosend = "{}:0:{}".format(ename, str(e))
                  if PY3:
                      tosend = tosend.encode("utf-8")
  
                  os.write(exec_err_pipe_write, tosend)
                  os.close(exec_err_pipe_write)
                  os._exit(1)
  
          try:
              if env is None:
                  os.execv(command, argv)
              else:
                  os.execvpe(command, argv, env)
          except OSError as err:
              # [issue #119] 5. If exec fails, the child writes the error
              # code back to the parent using the pipe, then exits.
              tosend = "OSError:{}:{}".format(err.errno, str(err))
              if PY3:
                  tosend = tosend.encode("utf-8")
              os.write(exec_err_pipe_write, tosend)
              os.close(exec_err_pipe_write)
              os._exit(os.EX_OSERR)
  
      # Parent
      inst = cls(pid, fd)
  
      # Set some informational attributes
      inst.argv = argv
      if env is not None:
          inst.env = env
      if cwd is not None:
          inst.launch_dir = cwd
  
      # [issue #119] 2. After forking, the parent closes the writing end
      # of the pipe and reads from the reading end.
      os.close(exec_err_pipe_write)
      exec_err_data = os.read(exec_err_pipe_read, 4096)
      os.close(exec_err_pipe_read)
  
      # [issue #119] 6. The parent reads eof (a zero-length read) if the
      # child successfully performed exec, since close-on-exec made
      # successful exec close the writing end of the pipe. Or, if exec
      # failed, the parent reads the error code and can proceed
      # accordingly. Either way, the parent blocks until the child calls
      # exec.
      if len(exec_err_data) != 0:
          try:
              errclass, errno_s, errmsg = exec_err_data.split(b":", 2)
              exctype = getattr(
                  builtins, errclass.decode("ascii"), Exception
              )
  
              exception = exctype(errmsg.decode("utf-8", "replace"))
              if exctype is OSError:
                  exception.errno = int(errno_s)
          except:
              raise Exception(
                  "Subprocess failed, got bad error data: %r"
                  % exec_err_data
              )
          else:
              raise exception
  
      try:
          inst.setwinsize(*dimensions)
      except IOError as err:
          if err.args[0] not in (
              errno.EINVAL,
              errno.ENOTTY,
              errno.ENXIO,
          ):
              raise
  
      return inst
  
imports: import codecs
  import errno
  import fcntl
  import io
  import os
  import pty
  import resource
  import signal
  import struct
  import sys
  import termios
  import time
  from pty import STDIN_FILENO, CHILD
  from .util import which, PtyProcessError
label_desc: Use image node_id 2 for calling the PtyProcess obj's underlying member method code with example usage: obj.spawn(cls, argv, cwd, env, echo, preexec_fn, dimensions, pass_fds) and returns: inst