首页 > 解决方案 > How to make a Haskell suprocess called from Python to not close after one use?

问题描述

I have a simple .exe file compiled from Haskell that just prints to stdout everything it receives to stdin:

module Main where

main = do
  command <- getLine
  putStrLn command
  main

And I have a Python file that tries to send two lines to the subprocess:

from subprocess import Popen, PIPE, STDOUT

p = Popen(['main.exe'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)  

def send_command(arg):
    print("Sending command: "+arg)  
    response = p.communicate(input=arg)[0].decode()
    print("Response: "+response+"\n")
    return response

send_command("Test1")
send_command("Test2")

It works the first time around, but not the second, apparently because it considers the input completed:

Sending command: Test1
Response: Test1
main.exe: <stdin>: hGetLine: end of file


Sending command: Test2
Traceback (most recent call last):
  File ".\test.py", line 12, in <module>
    send_command("Test2")
  File ".\test.py", line 7, in send_command
    response = p.communicate(input=arg)[0].decode()
  File "C:\Python27\lib\subprocess.py", line 483, in communicate
    return self._communicate(input)
  File "C:\Python27\lib\subprocess.py", line 722, in _communicate
    self.stdin.write(input)
ValueError: I/O operation on closed file

I don't know if the fault lies with Python or Haskell; other subprocesses for as expected when called from Python, and the Haskell file works as expected when called from the command line, but they just refuse to work together. How to fix this?

Edit:

I replaced the communicate with direct read\write:

from subprocess import Popen, PIPE, STDOUT

p = Popen(['main.exe'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)  

def send_command(arg):
    print("Sending command: "+arg)  
    p.stdin.write(arg+"\n")
    response = p.stdout.readline().decode()
    print("Response: "+response+"\n")
    return response

send_command("Test1")
send_command("Test2")

And made sure (just in case) that the .exe properly terminates lines:

module Main where

main = do
  command <- getLine
  putStrLn (command ++ "\n")
  main

And now the program just stops and does nothing at this point:

Sending command: Test1

Am I supposed to somehow "flush" the input or what?

标签: pythonhaskellsubprocesseof

解决方案


Here is the documentation for the subprocess.Popen.communicate function you're calling:

Popen.communicate(input=None, timeout=None)

Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate.

(my emphasis).

You can just write to p.stdin and read from p.stdout if you don't want all the other stuff communicate does.

I don't know if the fault lies with Python or Haskell

This isn't intended as a criticism, but a helpful hint: the fault lies with whoever didn't read the documentation for the function they called. It's free, read it!


推荐阅读