Home >Backend Development >Python Tutorial >Why Does `subprocess.readlines()` Hang When Streaming a Ruby File in Python?

Why Does `subprocess.readlines()` Hang When Streaming a Ruby File in Python?

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-12-06 12:59:15900browse

Why Does `subprocess.readlines()` Hang When Streaming a Ruby File in Python?

Python subprocess.readlines() hangs

Problem:

In the following Python code, using subprocess.readlines() to stream a Ruby file causes the program to hang indefinitely, preventing the final print statement from being executed:

from subprocess import Popen, PIPE, STDOUT
import pty
import os

file_path = '/Users/luciano/Desktop/ruby_sleep.rb'
command = ' '.join(["ruby", file_path])
master, slave = pty.openpty()
proc = Popen(command, bufsize=0, shell=True, stdout=slave, stderr=slave, close_fds=True)
stdout = os.fdopen(master, 'r', 0)

while proc.poll() is None:
    data = stdout.readline()
    if data != "":
        print(data)
    else:
        break

print("This is never reached!")

Cause:

The issue here stems from the use of pty, which is intended for pseudo-terminal handling. This typically causes line-buffering on the Ruby side, resulting in the readline() function waiting indefinitely for a newline character.

Solutions:

There are several options to resolve this issue:

1. Using pexpect:

pexpect enables line-buffering in a non-interactive setting:

import sys
import pexpect

pexpect.run("ruby ruby_sleep.rb", logfile=sys.stdout)

2. Using stdbuf:

stdbuf can be used to enable line-buffering in non-interactive mode:

from subprocess import Popen, PIPE, STDOUT

proc = Popen(['stdbuf', '-oL', 'ruby', 'ruby_sleep.rb'],
             bufsize=1, stdout=PIPE, stderr=STDOUT, close_fds=True)
for line in iter(proc.stdout.readline, b''):
    print line,
proc.stdout.close()
proc.wait()

3. Using pty from the standard library:

import errno
import os
import pty
from subprocess import Popen, STDOUT

master_fd, slave_fd = pty.openpty()  # provide tty to enable
                                     # line-buffering on ruby's side
proc = Popen(['ruby', 'ruby_sleep.rb'],
             stdin=slave_fd, stdout=slave_fd, stderr=STDOUT, close_fds=True)
os.close(slave_fd)
try:
    while 1:
        try:
            data = os.read(master_fd, 512)
        except OSError as e:
            if e.errno != errno.EIO:
                raise
            break # EIO means EOF on some systems
        else:
            if not data: # EOF
                break
            print('got ' + repr(data))
finally:
    os.close(master_fd)
    if proc.poll() is None:
        proc.kill()
    proc.wait()
print("This is reached!")

The above is the detailed content of Why Does `subprocess.readlines()` Hang When Streaming a Ruby File in Python?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn