title: Forcing subprocess.Popen to write stdout/stderr to file-like object in python using write() function and not fileno()
body: <p>My goal is to open a process using <code>subprocess.Popen</code> in python, and have this process pipe its stdout and stderr to a custom RingBuffer class that I've written, allowing me to periodically inspect the contents of the buffer from the same space I instantiated the subprocess from. This is important, I know there are ways to make a separate program, pipe the output of the subprocess to the <code>stdin</code> of that ringbuffer program, but then I have to go and manually inspect some underlying file that contains the ring buffer contents, etc, etc. The ideal thing would be to connect the output of the subprocess to some object that I have access to.</p>
  
  <p>First, from the documenation for <code>subprocess</code> (python 2.X) (<a href="https://docs.python.org/2/library/subprocess.html" rel="nofollow noreferrer">https://docs.python.org/2/library/subprocess.html</a>)</p>
  
  <blockquote>
    <p>stdin, stdout and stderr specify the executed program’s standard
    input, standard output and standard error file handles, respectively.
    Valid values are PIPE, an existing file descriptor (a positive
    integer), an existing file object, and None. PIPE indicates that a new
    pipe to the child should be created. With the default settings of
    None, no redirection will occur; the child’s file handles will be
    inherited from the parent. Additionally, stderr can be STDOUT, which
    indicates that the stderr data from the child process should be
    captured into the same file handle as for stdout</p>
  </blockquote>
  
  <p>"an existing file object", so I assume if I make a class that conforms to the <code>file</code> interface it should work, right?</p>
  
  <p>Let's say I've made a class like this</p>
  
  <pre><code>class RingBuffer(object):
  
      def __init__(max_size=1024*1024):
        self.max_size = max_size
        self.current_size = 0
  
  
      def write(self, data):
          self.current_size += len(data)
          self.data.append(data)
          if self.current_size &gt;= self.max_size_bytes:
              while self.current_size &gt;= self.trim_size_bytes:
                  try:
                      popped = self.data.pop()
                      self.current_size -= len(popped)
                  except IndexError as e:
                      break
  
  def writelines(self, sequence):
      for item in sequence:
          self.write(item)
  
  def dumps(self):
      ret = [line for line in self.data]
      return '\n'.join(ret)
  
  def clear(self):
      self.data.clear()
      self.current_size = 0
  </code></pre>
  
  <p>granted there are likely bugs in this program but you get the gist, it exposes a <code>write()</code> function and writes data to a circular buffer, trimming the buffer to a certain size when it gets too bug, and letting the user recover the data when they want with the <code>dumps()</code> function.</p>
  
  <p>Now, if I try something like this</p>
  
  <pre><code>r = RingBuffer()
  pr = subprocess.Popen(["timeout", "15", "yes"], stdout=r, stderr=subprocess.STDOUT)
  Traceback (most recent call last):
    File "&lt;stdin&gt;", line 1, in &lt;module&gt;
    File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 382, in __init__
      errread, errwrite), to_close = self._get_handles(stdin, stdout, stderr)
    File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 818, in _get_handles
      c2pwrite = stdout.fileno()
  AttributeError: 'RingBuffer' object has no attribute 'fileno'
  </code></pre>
  
  <p>okay, so my "file-like" object is missing the <code>fileno()</code> function to conform to the file interface. This is where the issue lays.. why does it need a fileno? Why can't it just use my supplied <code>write()</code> function? I'm assuming that it is going to by-pass my <code>write</code> function and instead use the <code>fileno</code> to write directly to the file?</p>
  
  <p>Let's say I add in a stub of that function</p>
  
  <pre><code>def fileno()
      return None
  </code></pre>
  
  <p>then this happens</p>
  
  <pre><code>r = RingBuffer()
  pr = subprocess.Popen(["timeout", "15", "yes"], stdout=r, stderr=subprocess.STDOUT)
  Traceback (most recent call last):
    File "&lt;stdin&gt;", line 1, in &lt;module&gt;
    File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 390, in __init__
      errread, errwrite)
    File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 1024, in _execute_child
      raise child_exception
  OSError: [Errno 2] No such file or directory
  </code></pre>
  
  <hr>
  
  <p>so my question is: how can I force <code>subprocess.Popen</code> to use my <code>write()</code> function for my <code>file</code>-like object instead of trying to write directly to the file handle returned from a non-existent <code>fileno()</code> function? If there is no way to do this.. is there any way to accomplish what I want here? </p>
  
  <p>I know that theoretically I could make some file, <code>/tmp/ringlog.txt</code>, and open that file on instantiation of the class, then have the program write to that file, and have my program periodically look at the file and keep it under the <code>max_size</code> using a similar ringbuffer algorithm, but that's a mess.</p>
  
  <p>Another option is to make a program that reads stdin, writes to a file, and ringbuffers the content to keep the file under a certain size, but then I'm still dealing with actual file, I just want to keep the contents in memory and accessible from the calling python environment.</p>