How to execute a Python script and retrieve output (data and errors) in Node.js

How to execute a Python script and retrieve output (data and errors) in Node.js

Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices, however there are few computational tasks for which you would prefer Python if you're highly concerned about the speed in your project.

But on the other hand, you may probably want to still work with Node.js, therefore you need to learn how to execute a Python script from Node. In this case, we'll cover the most basic points as how to execute a Python script and how to retrieve the generated output (both in standard output and error output).

Before continue with the tutorial, you need a python script to execute. Therefore in this article, we are going to use the following python script (you can use it in case you don't have any at hand or you want to test):

# script.py
my_name = 'Carlos'
my_age = 18 # not a lie
my_height = 172 # cm
my_weight = 71 # kg
my_eyes = 'Brown'
my_teeth = 'White'
my_hair = 'Black'

print "Let's talk about %s." % my_name
print "He's %d centimeters tall." % my_height
print "He's %d kilograms heavy." % my_weight
print "Actually that's not too heavy."
print "He's got %s eyes and %s hair." % (my_eyes, my_hair)
print "His teeth are usually %s depending on the coffee." % my_teeth

# this line is tricky, try to get it exactly right
print "If I add %d, %d, and %d I get %d. I don't know what that means but, whatever." % (
    my_age, my_height, my_weight, my_age + my_height + my_weight)

1) Using a library

In order to execute a python script easily and without effort, you can use the python-shell library to achieve your goal. This module is a simple way to run Python scripts from Node.js with basic but efficient inter-process communication and better error handling.

To install this module in your project, execute the following command in your node command prompt:

npm install python-shell

Python shell uses the Child Process under the hood to achieve this task. Read more about the API of this module here or visit the repository in Github.

var myPythonScriptPath = 'script.py';

// Use python shell
var PythonShell = require('python-shell');
var pyshell = new PythonShell(myPythonScriptPath);

pyshell.on('message', function (message) {
    // received a message sent from the Python script (a simple "print" statement)
    console.log(message);
});

// end the input stream and allow the process to exit
pyshell.end(function (err) {
    if (err){
        throw err;
    };

    console.log('finished');
});

Generating the following result in the console:

Executing python script in node.js and retrieve the output

Note that the script assumes that you already have Python available from the console as an environment variable. If this is not the case for you, don't worry, Python shell allow you to set some basic options at the execution (i.e the path to the python executable):

var PythonShell = require('python-shell');

var options = {
    mode: 'text',
    pythonPath: 'path/to/python',
    pythonOptions: ['-u'],
    scriptPath: 'path/to/my/scripts',
    args: ['value1', 'value2', 'value3']
};

PythonShell.run('script.py', options, function (err, results) {
    if (err) throw err;
    // results is an array consisting of messages collected during execution
    console.log('results: %j', results);
});

Executing python script with arguments

Some python scripts require arguments in order to be executed. Python shell allow you to add arguments using the options parameter when you run a script.

The following python script (script.py) should list all the arguments at the moment of execution:

import sys

print "\n".join(sys.argv)

For example, in order to execute a script in Node.js that could be executed in the following way directly with python in the console:

python script.py "my First Argument" "My Second Argument" --option=123

We only need to provide an array as value in the args key in the options object with the corresponding values:

var PythonShell = require('python-shell');

var options = {
    mode: 'text',
    args: ['my First Argument', 'My Second Argument', '--option=123']
};

PythonShell.run('script.py', options, function (err, results) {
    if (err) throw err;
    // results is an array consisting of messages collected during execution
    console.log('results: %j', results);
});

And that's it! the python shell module makes this task easy to achieve and of a comprehensive way.

Providing data from Node.js to Python

To send data from Javascript to our Python script, we need to write text using the standard input (stdin) in the process.

With python shell, you can easily handle the standard input and send the information using the send method. In this example, we are going to send an array (in string format) and it will be processed with python later:

var PythonShell = require('python-shell');
var pyshell = new PythonShell('script.py');

pyshell.send(JSON.stringify([1,2,3,4,5]));

pyshell.on('message', function (message) {
    // received a message sent from the Python script (a simple "print" statement)
    console.log(message);
});

// end the input stream and allow the process to exit
pyshell.end(function (err) {
    if (err){
        throw err;
    };

    console.log('finished');
});

The python script should print the sum of the items in an array providen by Javascript using the standard input (stdin):

import sys, json

#Read data from stdin
def read_in():
    lines = sys.stdin.readlines()
    # Since our input would only be having one line, parse our JSON data from that
    return json.loads(lines[0])

def main():
    #get our data as an array from read_in()
    lines = read_in()

    # Sum  of all the items in the providen array
    total_sum_inArray = 0
    for item in lines:
        total_sum_inArray += item

    #return the sum to the output stream
    print total_sum_inArray

# Start process
if __name__ == '__main__':
    main()

The output in the Node.js console should be 15.

2) Using the built-in child_process module

If you don't want to depend on any library to achieve this task, then you can use the child_process to spawn the python environment and execute your script on it by yourself.

The child_process module provides the ability to spawn child processes in a manner that is similar, but not identical, to popen. This capability is primarily provided by the child_process.spawn function:

// The path to your python script
var myPythonScript = "script.py";
// Provide the path of the python executable, if python is available as environment variable then you can use only "python"
var pythonExecutable = "python.exe";

// Function to convert an Uint8Array to a string
var uint8arrayToString = function(data){
    return String.fromCharCode.apply(null, data);
};

const spawn = require('child_process').spawn;
const scriptExecution = spawn(pythonExecutable, [myPythonScript]);

// Handle normal output
scriptExecution.stdout.on('data', (data) => {
    console.log(uint8arrayToString(data));
});

// Handle error output
scriptExecution.stderr.on('data', (data) => {
    // As said before, convert the Uint8Array to a readable string.
    console.log(uint8arrayToString(data));
});

scriptExecution.on('exit', (code) => {
    console.log("Process quit with code : " + code);
});

In the previous script, we are already achieving most of the functionalities that the python-shell module has to offer. It requires the child_process module, then we use the spawn method to start python with the path of the python script as first parameter and add some listeners to the stdout and stderr properties in order to handle the output.

Executing python script with arguments

If you were attentive, then you know that we already used arguments at the initialization of the script in the spawn function. The path of the python script is already a parameter, so if you want to add more parameters feel free to add more values to the second parameter array of the spawn function:

const scriptExecution = spawn(pythonExecutable, ["my_Script.py", "Argument 1", "Argument 2"]);

Providing data from Node.js to Python

To send data from Javascript to our Python script, we need to write text using the standard input (stdin) in the process.

In this example, we are going to send an array (in string format using the JSON.stringify method) to Python:

const spawn = require('child_process').spawn;
const scriptExecution = spawn("python.exe", ["script.py"]);

// Handle normal output
scriptExecution.stdout.on('data', (data) => {
    console.log(String.fromCharCode.apply(null, data));
});

// Write data (remember to send only strings or numbers, otherwhise python wont understand)
var data = JSON.stringify([1,2,3,4,5]);
scriptExecution.stdin.write(data);
// End data write
scriptExecution.stdin.end();

The python script should print the sum of the items in an array providen by Javascript using the standard input (stdin):

import sys, json

#Read data from stdin
def read_in():
    lines = sys.stdin.readlines()
    # Since our input would only be having one line, parse our JSON data from that
    return json.loads(lines[0])

def main():
    #get our data as an array from read_in()
    lines = read_in()

    # Sum  of all the items in the providen array
    total_sum_inArray = 0
    for item in lines:
        total_sum_inArray += item

    #return the sum to the output stream
    print total_sum_inArray

# Start process
if __name__ == '__main__':
    main()

The output in the Node.js console should be 15.

Have fun !

Become a more social person