docs: def open(self, args=None, keep_log=False):
          # type: (Optional[Union[str, Sequence[str]]], Union[bool, int]) -> None
          """Open a connection to FORM.
  
          Open a connection to a new FORM process. The opened connection should
          be closed by :meth:`close`, which can be guaranteed by use of the
          "with" statement:
  
          >>> import form
          >>> with form.open() as formlink:
          ...     pass  # use formlink ...
  
          If this method is called for a link object that has an established
          connection to a FORM process, then the existing connection will be
          closed and a new connection will be created.
  
          The optional argument ``args`` is for the FORM command, a string or
          a sequence of strings. For example '/path/to/form' or ['tform', '-w4'].
          By default, the value of the environment variable ``$FORM`` is used if
          set, otherwise 'form' will be used.
  
          The other argument ``keep_log`` indicates whether the log from FORM is
          kept and used as detailed information when an error occurs.
          If the value is >= 2, it specifies the maximum number of lines for
          the scrollback. The default value is False.
  
          Note
          ----
          In the current implementation, ``keep_log=True`` may cause a dead lock
          when the listing of the input is enabled and very long input is sent to
          FORM.
          """
          if args is None:
              if 'FORM' in os.environ:
                  args = os.environ['FORM']
              else:
                  args = 'form'
          if isinstance(args, string_types):
              args = shlex.split(args)  # Split the arguments.
          elif isinstance(args, (list, tuple)):
              args = list(args)  # As a modifiable mutable object.
          else:
              raise TypeError("invalid args = {0}".format(args))
  
          self.close()
  
          fd_childin, fd_parentout = os.pipe()
          fd_parentin, fd_childout = os.pipe()
          fd_loggingin, fd_loggingout = os.pipe()
  
          pid = os.fork()
          if pid:
              # parent process
              os.close(fd_childin)
              os.close(fd_childout)
              os.close(fd_loggingout)
  
              parentin = os.fdopen(fd_parentin, 'r')
              parentout = os.fdopen(fd_parentout, 'w')
              loggingin = os.fdopen(fd_loggingin, 'r')
  
              # FORM sends 'pid\n'.
              s = parentin.readline()
              if not s:
                  os.waitpid(pid, 0)
                  parentin.close()
                  parentout.close()
                  loggingin.close()
                  raise IOError('failed to read the first line from FORM')
              s = s.rstrip()
              formpid = int(s)
              # The parent must send 'pid,ppid\n'.
              s = s + ',{0}\n'.format(os.getpid())
              parentout.write(s)
              parentout.flush()
              # FORM sends 'OK' (in init.frm).
              s = parentin.read(2)
              if s != 'OK':
                  os.waitpid(pid, 0)
                  parentin.close()
                  parentout.close()
                  loggingin.close()
                  raise IOError('failed to establish the connection to FORM')
              # Change the prompt.
              parentout.write('#prompt {0}\n'.format(self._PROMPT.strip()))
              # Read the first line of the FORM output.
              head = loggingin.readline().rstrip()
  
              set_nonblock(fd_parentin)
              set_nonblock(fd_loggingin)
  
              self._closed = False
              self._head = head
              if keep_log:
                  if keep_log >= 2:
                      log = collections.deque(maxlen=keep_log)  # type: Any
                      self._log = log  # hack typeshed for Python 2
                      assert self._log is not None
                      self._log.append(head)
                  else:
                      self._log = []
                      self._log.append(head)
              else:
                  self._log = None
                  # Turn off the listing of the input.
                  parentout.write('#-\n')
              self._childpid = pid
              self._formpid = formpid
              self._parentin = PushbackReader(parentin)
              self._parentout = parentout
              self._loggingin = PushbackReader(loggingin)
          else:
              # child process
  
              # NOTE: Coverage fails to collect data from child processes when
              #       the os.fork+os._exit pattern is used.
              #       https://bitbucket.org/ned/coveragepy/issues/310
  
              os.close(fd_parentout)
              os.close(fd_parentin)
              os.close(fd_loggingin)
              os.dup2(fd_loggingout, sys.__stdout__.fileno())
  
              args.append('-M')
              args.append('-pipe')
              args.append('{0},{1}'.format(fd_childin, fd_childout))
              args.append(FormLink._INIT_FRM)
  
              # In Python 3.2, subprocess.Popen() on UNIX changed the default
              # value for close_fds from False to True, in order to stop leaking
              # file descriptors. File descriptors to be kept open should be
              # specified by pass_fds.
              if sys.version_info[0:2] < (3, 2):
                  subprocess.call(args, shell=False)
              else:
                  subprocess.call(args, shell=False,
                                  pass_fds=(fd_childin,
                                            fd_childout,
                                            fd_loggingout))
  
              os.close(fd_childin)
              os.close(fd_childout)
              os.close(fd_loggingout)
              os._exit(0)