So I have node calling a python scrip but I want to get an object back from python.
I'm currently using Python-shell (https://www.npmjs.com/package/python-shell) but the problem is its listening so I can't actually send the data I get from it
shell.on('message', function(message){
ah = message;
console.log(message);
console.log("#");
});
console.log(ah);
var host = {
"hostName":ah
};
console.log(host);
return response.send(200, host);
the last section of the code will execute well before the python script returns anything via print()
(I also can't put the response.send in the listening function because it may send every time the python script prints)
is there another way of doing this?
If you want to return the results of a script to the client, just wrap this call: PythonShell.run in in a router endpoint:
app.get('/somepath', (req, res)=>{
PythonShell.run('my_script.py', options, function (err, results) {
if (err) throw err;
// results is an array consisting of messages collected during execution
res.send('results: %j', results);
});
});
Related
I'm writing a simple web app to get a handle on how node child processes work. Basically you enter your name into an angular frontend which passes the name to an express backend in a javascript object. The backend passes the name as an argument to a simple python script as a command line argument using the child_process module. Theres nothing wrong with the front end and the name gets successfully passed to the backend but when I call stdout on the python process it doesn't work. There aren't any error messages.
Heres the express code:
app.post('/api', (req, res, next) => {
console.log(req.body.name);
const spawn = require('child_process').spawn;
const process = spawn('python3', ['./hello.py', req.body.name]);
process.stdout.on('data', (data) => {
console.log(data);
res.status(200).json({greeting: data});
});
});
I put two console.log statements in the code to debug it. The first one prints the data but the second one inside the stdout function isn't called at all. The python script is in the same folder as the app.js express file so I'm pretty sure theres nothing wrong with the file path.
Here's the python script:
import sys
print('hello' + sys.argv[1])
sys.stdout.flush()
When I run it in the command line it works exactly as expected but I included it anyway just in case.
Process.stdout.on will keep on streaming until the end event. The code is wrong because you are actually sending response for every time there is some value in stdout. And you cant set the response header more than once. Try writing the code in below way. Thanks
let output;
Process.stdout.on("data", (data) => {
output += data;
});
Process.on("end", () => {
// send response here
});
close will trigger when your data completes
app.get("/list-account", async (req, res) => {
try {
let array = "";
let response = await child.spawn(
path.join(__dirname, "xcv-alpha-keychain.exe"),
["listaccounts"]
);
await response.stdout.on("data", (data) => {
const stdout = data.toString();
console.log("stdout", stdout);
array += stdout;
// return res.status(200).json({ array });
});
response.stderr.on("data", (data) => {
return res.status(500).send(data.toString());
});
response.on("error", (error) => {
return res.status(500).send({ error });
});
response.on("close", (code) => {
return res.status(200).json({ array, code });
});
} catch (error) {
return res.status(500).send(["a", "b", "c"]);
}
});
Instead of
console.log(data)
use
console.log(data.toString())
I have a python script which deals with image, reading and extracting text from image. Now i have a requirement where i have to call that python script from node js. My issue is how do i get the response from python script in node ?
Python script :-
response = image_to_dict('test.jpg', bucketname)
detections = dict_to_detections(response)
entities = list_to_entities(detections.lines)
print("Payer is {payerName}".format(payerName=extractPayer(entities.orgs,
response)))
print("Member name is
{memberName}".format(memberName=extractMemberName(entities.persons)))
print("Member ID is
{memberId}".format(memberId=extractMemberId(detections.lines)))
Node js :-
var PythonShell = require('python-shell');
PythonShell.run('test.py', function (err) {
if (err) throw err;
console.log('finished');
});
Now i need what i print in python script e.g Payer Name as response in node js.
Any input would be greatfull.
Thanks in advance
With error you need to pass another parameter in the function which will give you array of messages printed in the shell script.
PythonShell.run('test.py', options, function (err, results) {
if (err) throw err;
// results is an array consisting of messages collected during execution
console.log('results: %j', results);
});
More: https://www.npmjs.com/package/python-shell
as stated in the doc you just need to provide another argument in your callback
PythonShell.run('script.py', function (err, results) {
if (err) throw err;
console.log(results);
});
Runs the Python script and invokes callback with the results. The
callback contains the execution error (if any) as well as an array of
messages emitted from the Python script.
I'm creating an API with NodeJS. Every request returns a JSON. Some requests call to a python script and I want to send the JSON generated by python to the user. The code would look like:
child = child_process.spawn(cmd, args);
child.stdout.on('data', (chunk) => {
res.write(chunk);
});
child.on('error', function(err) {
res.status(500).json({...});
});
child.on('close', (code) => {
res.end();
});
The problem with this code is that I can't check if the python output is a JSON. Maybe python writes warnings, error...
What can I do to prevent the user will get something different to JSON?.
EDIT
Right now my code is:
var output = [];
command.stdout.on('data', (chunk) => {
output.push(chunk)
});
command.on('close', (code) => {
var stdout = output.join('');
json_cmd = tryParseJSON(stdout)
if (json_cmd)
res.send(json_cmd)...
});
But, I don't want to load all the stdout in a variable. But if I don't do that, I can check if the stdout is a JSON. Can I force python to print just json?. Using always json.dumps and a global try catch would be enough?
Thanks.
Instead of using spawn, you probably want to use exec, which will wait for the Python process to exit and provide you with its output (which you can subsequently try to parse as JSON):
const exec = require('child_process').exec;
...
exec(cmdline, (err, stdout, stderr) => {
if (err) return res.status(500).json({...});
// Try to parse stdout as JSON:
try {
res.json(JSON.parse(stdout));
} catch(e) {
res.status(500).json({...});
}
});
So you need a streaming JSON verifier in NodeJS. The problem is that if you start streaming the json data over the network, and find an error in the JSON halfways, you cannot rollback the traffic to the http headers and change 200 ok to 500 ise. If you want to check the output first you have to accumulate it in the server before sending.
Your current code would do the same. If an error event comes the client will receive a 200 ok with a half stdout and a json object at the end. (Or the response object throws an error if you try to set the status code after it has been sent, I don't know how is this case handled.)
I am trying to host a local server (using Node.js) on a Raspberry Pi. The Pi has an ADC (MCP3008) connected to it, and I have a Python script that continuously samples the ADC and prints the current value. I want to have the Node server run the Python script, and whenever it sees a print statement, to just do a console.log(current value) for the time being. I am new to Node and web development in general, so it may be something simple that I'm missing so that Node will continuously receive data from the Python script. I'm trying to use Socket.io at the moment, as that seems to make sense as the method for Node to see changes from the Python script, but maybe this isn't the best way to do it. The basic webpage is from a tutorial I found (http://www.jaredwolff.com/blog/raspberry-pi-getting-interactive-with-your-server-using-websockets/). The code I am currently using is here:
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, url= require('url')
, fs = require('fs')
, gpio = require('onoff').Gpio
, PythonShell = require('python-shell');
app.listen(5000);
function handler (req, res) {
var path = url.parse(req.url).pathname;
if (path == '/') {
index = fs.readFile(__dirname+'/public/index.html',
function(error,data) {
if (error) {
res.writeHead(500);
return res.end("Error: unable to load index.html");
}
res.writeHead(200,{'Content-Type': 'text/html'});
res.end(data);
});
} else if( /\.(js)$/.test(path) ) {
index = fs.readFile(__dirname+'/public'+path,
function(error,data) {
if (error) {
res.writeHead(500);
return res.end("Error: unable to load " + path);
}
res.writeHead(200,{'Content-Type': 'text/plain'});
res.end(data);
});
} else {
res.writeHead(404);
res.end("Error: 404 - File not found.");
}
}
// Python
var pyshell = new PythonShell('mcp3008.py');
pyshell.run('mcp3008.py', function (err, results) {
if (err) throw err;
console.log('Results: %j', results);
});
io.sockets.on('connection', function (socket) {
pyshell.on('message', function (message) {
console.log(message);
});
});
Thank you for any hints or help that you can provide!
As jfriend00 recommended, I looked into node.js solutions. I had previously tried this, using several mcp3008 packages available on npm, but none of them successfully installed on my Raspberry Pi (model B). However, I ended up rewriting the one located here (https://github.com/fiskeben/mcp3008.js) as a separate .js file, included it with my code (along with some work from the npm spi library), and put it into a loop to read the ADC pin. That's working for now, and should be good enough for my current needs, but it still seems like a more processor-intensive solution than it should be. Thanks for your feedback!
I've this simple Python script print out a message every second:
#!/usr/bin/python
import time
while True:
print u"Message"
time.sleep(1)
I'm trying to integrate a 3rd party Python script with the above structure with Node.js using python-shell.
I'm having this JS script to get all messages from the Python script:
var PythonShell = require('python-shell');
var options = {
scriptPath: './'
};
var pyshell = new PythonShell('test.py',options);
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');
});
But it seems, that the while True in Python cause that the on-event is not called. How can I solve this? Can I change the loop inside the Python script to something compatible with python-shell?
You need to flush sys.stdout as the output is buffered because it is piped:
import time
import sys
while True:
print u"Message"
sys.stdout.flush()
time.sleep(1)
You will receive the output immediately once flushed:
$ nodejs n.js
Message
Message
Message
.....
You may be able to set the buffering to line buffered or unbuffered when you start the shell but I am not overly familiar with nodejs.
There is actually a way to set the -u flag to get unbuffered output with the pythonOptions flag:
var PythonShell = require('python-shell');
var pyshell = new PythonShell('test.py',{scriptPath:"./", pythonOptions: ['-u']});
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 output will be unbuffered so there will be no need to flush stdout.