Reading Python from stdin hangs when interacting with ruby ​​code

I was trying to insert python and ruby ​​codes into conversation and I found methods from this link ( http://www.decalage.info/python/ruby_bridge )

I tried the last method using stdin and stdout to transfer information. I've made some changes to the source code to match python 3.4, but I'm not sure if the code I changed messed things up. My python program always hangs when reading from stdin and nothing was printed. I'm not familiar with stdin and stdout, so I'm just wondering why this isn't working.

Here are my ruby ​​codes:

$stdin.set_encoding("utf-8:utf-8")
$stdout.set_encoding("utf-8:utf-8")

while cmd = $stdin.gets

    cmd.chop!
    if cmd == "exit"
        break
    else
        puts eval(cmd)
        puts "[end]"
        $stdout.flush

    end
end

      

I'm not sure if it is possible to set internal encoding and external encoding like this. And here are my python codes:

from subprocess import Popen, PIPE, STDOUT

print("Launch slave process...")
slave = Popen(['ruby', 'slave.rb'], stdin=PIPE, stdout=PIPE, stderr=STDOUT)

while True:
    line = input("Enter expression or exit:")
    slave.stdin.write((line+'\n').encode('UTF-8'))
    result = []
    while True:
        if slave.poll() is not None:
            print("Slave has terminated.")
            exit()

        line = slave.stdout.readline().decode('UTF-8').rstrip()
        if line == "[end]":
            break
        result.append(line)
    print("result:")
    print("\n".join(result))

      

When I try to run the python script, type "3 * 4" and hit "Enter", nothing shows up until I hacked the process manually with exit code 1 and "KeyboardInterrupt Exception". I've been struggling with this issue for a long time and I don't know what went wrong ... Thanks in advance for any potential help!

+3


source to share


1 answer


The difference is that it bufsize=-1

defaults to Python 3.4, and therefore slave.stdin.write()

does not send the string to the subprocess ruby

immediately. The quick fix is ​​to add a call slave.stdin.flush()

.

#!/usr/bin/env python3
from subprocess import Popen, PIPE

log = print
log("Launch slave process...")
with Popen(['ruby', 'slave.rb'], stdin=PIPE, stdout=PIPE, 
           bufsize=1, universal_newlines=True) as ruby:
    while True:
        line = input("Enter expression or exit:")
        # send request
        print(line, file=ruby.stdin, flush=True)
        # read reply
        result = []
        for line in ruby.stdout:
            line = line.rstrip('\n')
            if line == "[end]":
                break
            result.append(line)
        else: # no break, EOF
            log("Slave has terminated.")
            break
        log("result:" + "\n".join(result))

      



It uses universal_newlines=True

to enable text mode. It uses locale.getpreferredencoding(False)

bytes to decode. If you want to force the encoding utf-8

regardless of locale settings, then drop universal_newlines

and wrap the pipes in io.TextIOWrapper(encoding="utf-8")

( sample code - it also shows correct pipe exception handling ).

+2


source







All Articles