code: def communicate(self, input=None):
          
  
          # Optimization: If we are only using one pipe, or no pipe at
          # all, using select() or threads is unnecessary.
          if [self.stdin, self.stdout, self.stderr].count(None) >= 2:
              stdout = None
              stderr = None
              if self.stdin:
                  if input:
                      try:
                          self.stdin.write(input)
                      except IOError as e:
                          if e.errno != errno.EPIPE and e.errno != errno.EINVAL:
                              raise
                  self.stdin.close()
              elif self.stdout:
                  stdout = _eintr_retry_call(self.stdout.read)
                  self.stdout.close()
              elif self.stderr:
                  stderr = _eintr_retry_call(self.stderr.read)
                  self.stderr.close()
              self.wait()
              return (stdout, stderr)
  
          return self._communicate(input)
docs: Interact with process: Send data to stdin.  Read data from
          stdout and stderr, until end-of-file is reached.  Wait for
          process to terminate.  The optional input argument should be a
          string to be sent to the child process, or None, if no data
          should be sent to the child.
  
          communicate() returns a tuple (stdout, stderr).