python-shell icon indicating copy to clipboard operation
python-shell copied to clipboard

Messages inside input() are not flushed before keep waiting user iteraction

Open LeonardoRick opened this issue 5 years ago • 4 comments

Bug description When or program relies on a python library that has something like x = input('Please, enter your info: ') the phrase 'Please enter your info: ' is not sent to the .on('message', m => {}) listener from python-shell library and the program keep stuked waiting user input, but the user don't know what should be inputed.

Python code

x = input('Please, enter your info: ')
print(x)

Javascript code

import path from 'path';
import { PythonShell } from 'python-shell';

const rootDir = path.dirname(__dirname);

export const pythonOptions: Options = {
    mode: 'text',
    pythonPath: '/usr/bin/python',
    pythonOptions: ['-u'], // get print results in real-time
  };

pythonOptions.scriptPath = path.join(rootDir, 'python', `id1234`); // currentFolder/python/id1234/start.py
const python = new PythonShell('start.py', pythonOptions);
python
.on('message', (line: string) => {
  console.log(line) // this line do not print 'Please, enter your info:' **before** I input the data
})
.on('error', err => {
  console.log(err);
})
.on('close', () => {
    console.log('program finished')
});
setTimeout(() => {
    python.send('this is my info');  // everything is printed after this sending this 
}, 100000);

Expected behavior 'Please, enter your info: ' should be sent to .on('message', m => {}) listener before the program keep waiting user input. It should be printered before, as it happens when python program is runned from the terminal

Actual behavior 'Please, enter your info: ' is logged on .on('message', m => {}) only after user send his input. If he never send, it's never printed

Other Information

  • OS: Ubuntu 18.04 and Ubuntu 20.04
  • Python Version: 3.8
  • Node Version: 14.7

LeonardoRick avatar Sep 22 '20 16:09 LeonardoRick

Python's input function does not add a newline at the end. If you look in https://github.com/extrabacon/python-shell/blob/master/index.ts and search for "message" you would eventually find this:

        let parts = (''+data).split(newline);

        if (parts.length === 1) {
            // an incomplete record, keep buffering
            this._remaining = (this._remaining || '') + parts[0];
            return this;
        }

The code above buffers stdout until it receives a newline. input does not send a newline, so the message event is not immediately emitted.

You can fix this by adding a newline to the input message or moving the input message to a print().

Almenon avatar Sep 23 '20 03:09 Almenon

I'm using this workaround for now (move input message to a print). The problem is when the input field is inside a library, which forces me to edit the library code. I wish we had one way to do that without editing the third part code

LeonardoRick avatar Sep 23 '20 18:09 LeonardoRick

You can use the binary mode in pythonshell.

Almenon avatar Sep 24 '20 14:09 Almenon

Can you give me more details on how this would make it work? I'm not so familiar with that. Thanks a lot!

LeonardoRick avatar Sep 24 '20 17:09 LeonardoRick