So I'm working on trying to receive chess move data from the Leela Chess Zero engine. I am already done with all of the UI and other parts of the backend, and this is the last thing I need to implement. Unfortunately, I seem to have overestimated how simple subprocessing in Python is...
To explain a little more background, all I need to do is:
- Call/run
lc0.exe
in the local directory. I have managed this just fine. - Pass the commands
position startpos e2e4 e7e5 e1e2
,go nodes 100
,quit
via stdin in that order. This also seems to work fine according to what I can gauge via stderr. - Receive/read stdout. This is where I'm stuck.
Here's the things I've tried so far:
>>> from subprocess import Popen, PIPE, STDOUT
>>> p = Popen(['lc0'], stdout=PIPE, stdin=PIPE, stderr=PIPE)
>>> stdout_data = p.communicate(input=b'position startpos e2e4 e7e5 e1e2\ngo nodes 100\nquit')[0]
>>> stdout_data
b''
I get an empty byte string. I then tried a different method as a test:
>>> import subprocess
>>> subprocess.check_output(['lc0'], stderr=PIPE) #the following 3 lines is me typing into stdin
position startpos e2e4 e7e5 e1e2
go nodes 100
quit
b'info depth 1 seldepth 2 time 4081 nodes 4 score cp 12 nps 133 tbhits 0 pv e2e4 c7c5\r\ninfo depth 2 seldepth 3 time 4116 nodes 11 score cp 13 nps 166 tbhits 0 pv e2e4 c7c5 g1f3\r\ninfo depth 3 seldepth 4 time 4151 nodes 25 score cp 13 nps 247 tbhits 0 pv e2e4 c7c5 g1f3 e7e6\r\ninfo depth 3 seldepth 5 time 4218 nodes 68 score cp 13 nps 407 tbhits 0 pv e2e4 c7c5 b1c3 b8c6 g1e2\r\ninfo depth 4 seldepth 6 time 4312 nodes 134 score cp 13 nps 513 tbhits 0 pv e2e4 c7c5 b1c3 b8c6 g1f3 e7e5\r\nbestmove e2e4 ponder c7c5\r\n'
Eureka! I received the correct output from stdout. Now time to do it programatically:
>>> subprocess.check_output(['lc0'], stderr=PIPE, input=b'position startpos e2e4 e7e5 e1e2\ngo nodes 100\nquit')
b''
Bugger! What is happening here? I can confirm by removing the stderr=PIPE
argument that all of the commands apparently are indeed being run by the engine, but when all is said and done, stdout is empty when I pass the commands programatically. I've also tried using subprocess.stdin.write()
with identical results.
After digging a lot, I found that pexpect
might be more suitable for this use case. I installed pip install wexpect
and lo' and behold:
>>> from wexpect import spawn
>>> child = spawn("lc0")
...
Yup, it just hangs. Breaking with ^C gives me the exception pywintypes.error: (2, 'CreateFile', 'The system cannot find the file specified.')
, so I understandably feel less confident about using pexpect
instead of subprocess
, since I seem much closer to a solution with the latter.
Anyways, I'm convinced I'm misuing subprocess
somehow, but what exactly am I doing wrong? Why am I correctly receiving stdout
when passing commands through stdin
manually, but not when using the input=
argument?