0

First I should notice: I'm a python programmer with no knowledge about ruby!

Now, I need to feed stdin of a ruby program and capture stdout of the script with a python program.
I tried this (forth solution) and the code works in python2.7 but not in python3; The python3 code reads input with no output.

Now, I need a way to tie the ruby program to either python 2 or 3.

My try:

This code written with six module to have cross version compatibility.

  • python code:

    from subprocess import Popen, PIPE as pipe, STDOUT as out
    
    import six
    
    print('launching slave')
    slave = Popen(['ruby', 'slave.rb'], stdin=pipe, stdout=pipe, stderr=out)
    
    while True:
        if six.PY3:
            from sys import stderr
            line = input('enter command: ') + '\n'
            line = line.encode('ascii')
        else:
            line = raw_input('entercommand: ') + '\n'
        slave.stdin.write(line)
        res = []
        while True:
            if slave.poll() is not None:
                print('slave rerminated')
                exit()
            line = slave.stdout.readline().decode().rstrip()
            print('line:', line)
            if line == '[exit]': break
            res.append(line)
        print('results:')
        print('\n'.join(res))
    
  • ruby code:

    while cmd = STDIN.gets
        cmd.chop!
        if cmd == "exit"
            break
        else
            print eval(cmd), "\n"
            print "[exit]\n"
            STDOUT.flush
        end
    end
    

NOTE:

Either another way to do this stuff is welcomed! (like socket programming, etc.)
Also I think it's a better idea to not using pipe as stdout and use a file-like object. (like tempfile or StringIO or etc.)

ARF
  • 72
  • 7

2 Answers2

1

It's because of bufsize. In Python 2.x, default value was 0 (unbufffered). And in Python 3.x it changed to -1 (using default buffer size of system).

Specifying it explicitly will solve your problem.

slave = Popen(['ruby', 'slave.rb'], stdin=pipe, stdout=pipe, stderr=out, bufsize=0)

DEMO

falsetru
  • 357,413
  • 63
  • 732
  • 636
0

Below is the code on how I got it working with Ruby & Python3.

Ruby Slave

# read command from standard input:
while cmd = STDIN.gets
  # remove whitespaces:
  cmd.chop!
  # if command is "exit", terminate:
  if cmd == "exit"
    break
  else
    # else evaluate command, send result to standard output:
    print eval(cmd), "\n"
    print "[exit]\n"
    # flush stdout to avoid buffering issues:
    STDOUT.flush
  end
end

Python master

from subprocess import Popen, PIPE as pipe, STDOUT as out

print('Launching slave')
slave = Popen(['ruby', 'slave.rb'], stdin=pipe, stdout=pipe, stderr=out, bufsize=0)

while True:
    from sys import stderr
    line = input('Enter command: ') + '\n'
    line = line.encode('ascii')
    slave.stdin.write(line)
    res = []
    while True:
        if slave.poll() is not None:
            print('Slave terminated')
            exit()
        line = slave.stdout.readline().decode().rstrip()
        if line == '[exit]': break
        res.append(line)
    print('results:')
    print('\n'.join(res))