my Nodejs server with python scripts are combined via socket.io
I can run my python scripts and call its functions it works well until I send correct data.
the problem is when the python functions got error I can not handle them in node js
I want to understand before the python Scripts crashed I don't run them
I hope could explain the problem fluently
JS
function startScripts() {
let child = spawn('python', ['-u', __dirname + '/pyScripts/' + 'config.py']);
sockets.on('connection', function (socket) {
socket.join('config');
socks = socket;
});
child.stderr.on('data', function (err) {
console.log(err.toString());
});
child.stdout.on('data', function (data) {
console.log(data.toString());
});
}
function runPyFunction(data, callback) {
sockets.to('config').emit('run', data);
const handleResponse = (res) => {
if (res) {
return callback({ 'message': res, 'status': 'ok' }, null);
}
else {
return callback(null, { 'message': 'Function or file is not found', 'status': 'failed' });
}
};
socks.removeAllListeners();
socks.on('response', handleResponse);
}
app.post('/py', (req, res) => {
let data = req.body;
let userData = {
'filename': 'test',
'function': 'multiplication',
'args':[3]
}
runPyFunction(userData, (res2, err) => {
if (res) {
console.log('here is message');
console.log(res);
res.end(JSON.stringify(res2))
} else {
console.log('here is error');
console.log(err);
}
})
})
Python Config.py
def run_function(data):
for module in globals():
if data['filename'] == module:
for function in getmembers(globals()[module], isfunction):
if data['function'] == function[0]:
print(data)
if 'args' in data:
return sio.emit('response', function[1](*data['args']))
else:
return sio.emit('response', function[1]())
# Emit false if function or file not found
return sio.emit('response', False)
test.py
import os
def multiplication(number):
return number*number*number
Problem is : how to handle Errors when python scipts Die or crash ?
on the Code Above I made a communication between node js and py scipts
I added an API '/py' I send data to it (here is Mock data) and I tell I want to execute this File.py and this function name with these args
it searches to find the exact function.
it works fine; the problem is for example on the code above I must give int variable to py function when I send String data it downs and I can not handle it with my controller in node js.
how can I understand py Errors in node js ?
Related
I'm trying to execute a python script from node/express/tedious after a SQL Server stored procedure has finished running.
When the user clicks submit, a post request is sent to node/express:
const onSubmit = async (data) => {
await fetch('http://example.com:4001/foo/post/create', {
method: 'POST',
headers: authHeader(),
body: JSON.stringify({
fid: data.fid,
geomwkt: data.geomwkt,
srid: data.srid,
.
.
.
})
}).then(res => {
return res.text();
})
.then(data => console.log('Success:', data))
.catch(error => console.log('Error:', error))
history.push('/foo');
}
which in turn runs a SQL Server stored procedure via a router.post (express4/tedious):
router.post('/post/create', textParser, function (req, res) {
req.sql("exec create_alignment #align")
.param('align', req.body, TYPES.NVarChar)
.exec(res);
});
So now I want to execute a python script once the stored procedure has completed:
router.post('/post/create', textParser, function (req, res) {
req.sql("exec create_alignment #align")
.param('align', req.body, TYPES.NVarChar)
.exec(res);
const abc = JSON.parse(req.body);
exec('python3 /home/ubuntu/scripts/runthis.py ' + param1 + ' ' + param2, (error, stdout, stderr) => {
if (error) {
console.error(`error: ${error.message}`);
return;
}
if (stderr) {
console.error(`stderr: ${stderr}`);
return;
}
console.log(`stdout:\n${stdout}`);
});
});
But python script runs before the stored procedure has completed. So I've tried adding async/await into the mix:
router.post('/post/create', textParser, async function (req, res) {
await req.sql("exec create_alignment #align")
.param('align', req.body, TYPES.NVarChar)
.exec(res);
const abc = JSON.parse(req.body);
await exec('python3 /home/ubuntu/scripts/runthis.py ' + param1 + ' ' + param2, (error, stdout, stderr) => {
if (error) {
console.error(`error: ${error.message}`);
return;
}
if (stderr) {
console.error(`stderr: ${stderr}`);
return;
}
console.log(`stdout:\n${stdout}`);
});
});
But this doesn't seem to change anything. How do I run the python script after the stored procedure has completely finished?
From my understanding tedious doens't support ter async/await (but I'm quite new to node so maybe things have changed lately and I just don't know). You have to make sure the code you want to be executed after the procedure by manually coding the result of the promise.
I've wrote an article on this specifically, here:
Promises, Node, Tedious, Azure SQL. Oh My!
I'm using Electron + React JS as frontend which in turn will communicate the backend program(Python). I've looked for solutions and came up with something called python-shell library. This library helps to communicate or call out the backend.
upload.js
const handleSubmit = (e) => {
e.preventDefault()
console.log(file)
var pyShell = require('python-shell');
let options = {
mode: 'text',
args: [file]
};
pyShell.PythonShell.run('./py/backend.py', (err, results) => {
if (err) throw err;
console.log('results: ', results);
results.textContent = results[0];
});
}
backend.py
import sys
print('Hello from Python!')
sys.stdout.flush()
It shows me an error TypeError: child_process_1.spawn is not a function, and it shows the error location of index.ts(But there is no index.ts file in my entire directory).
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 want to access a python script and pass an image then wait for a json response . I should do this inside the "upload" function after getting the image.
Been searching but was not able to find a python-shell with sails. Since sails is built on top of node.js then there most be a way.
module.exports = {
fileUpload: function(req, res) {
res.writeHead(200, { 'content-type': 'text/html' });
res.end(
'<form action="http://localhost:1337/postIts/upload" enctype="multipart/form-data" method="post">' +
'<input type="text" name="title"><br>' +
'<input type="file" name="uploadFile"><br>' +
'<input type="submit" value="Upload">' +
'</form>'
)
},
upload: function(req, res) {
var uploadFile = req.file('uploadFile')
uploadFile.upload({
saveAs: 'image.png'
}, function onUploadComplete(err, files) {
if (err)
return res.serverError(err);
return res.json({
message: files.length + ' file(s) uploaded successfully!',
files: files[0]
});
});
}
};
I want to pass this uploaded image to python script and wait for a json output which I will return to the client. I havent tried anything because I am not sure of the proper way of doing this.
It should be something similar to this but i dont know the proper way. of doing it in my Controller.
there should be an import python-shell somewhere, maybe before the module.export ?
var PythonShell = require('python-shell');
var courseid=req.param('courseid');
sails.log.debug(coursed);
var options = {
args: [courseid]
};
PythonShell.run('word2vec.py', options, function (err, results) {
if (err) throw err;
console.log('results: %s', results[0]);
});
return res.ok();
So far I have tried installing pythonshell then tried an import from the controller and add the codes to the upload function which calls for the .py script but I get an error, I will upload a picture of the error. And here is the new code:
import { PythonShell } from 'python-shell';
var PythonShell = require('python-shell');
module.exports = {
upload: function(req, res) {
var uploadFile = req.file('uploadFile')
uploadFile.upload({
saveAs: 'image.png',
}, function onUploadComplete(err, files) {
let options = {
mode: 'text',
pythonOptions: ['-u'], // get print results in real-time
scriptPath: sails.config.pythonPath,
args: ['1233ID', files[0].fd]
};
PythonShell.run('main2.py', options, function(err, results) {
if (err) throw err;
console.log('results: %s', results);
});
if (err)
return res.serverError(err);
return res.json({
message: files.length + ' file(s) uploaded successfully!',
files: files[0].fd
});
});
}
};
see the screenshot for the error
I'm very new to nodejs what I try to do is upload an image with some data to nodejs API but before saving data to Mongo DB I try to do some process to this uploaded image using Python class then I will save the results to DB
so can I send uploaded image to python code and waite the result before saving any data to DB
my code is here
router.post('/img2text', upload.single('photo'), (req, res) => {
// Create the object for insertion into database
const Img2text = new img2text({
imgPath: req.file.path,
sender: req.body.sender,
processed: 0,
resultText: "no result",
});
/////////////////////////////////////////////////////////////start
var exec = require("child_process").exec;
exec(`python uploads/hello.py ${req.file.path}`,(error, stdout, stderr) => {
if (error) {
Img2text.processed=0;
Img2text.resultText='no result'
console.error(`exec error: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
Img2text.processed=1;
Img2text.resultText=stdout.toString('utf8');
console.log(`stderr: ${stderr}`);
console.log(req.query.firstname);
});
/////////////////////////////////////////////////////////end
// Save into database
Img2text.save((err) => {
// Check if error
if (err) {
res.json({ success: false, message: err });
} else {
console.log("img saved !!")
res.json({ success: true, message:img.resultText }); // Return success message
}
});
});
if the python code takes so long time my object will be empty?
any answer will be greatly appreciated
Have you tried to use Promise,If not refer this link Promise MDN. Just wrap your process in a Promise and when you finish with your process resolve it and save it to database.
router.post('/img2text', upload.single('photo'), (req, res) => {
// Receive your image
let pythonProcess = new Promise((resolve, reject)=>{
// do your process
reolve() // resolve with updated data
})
pythonProcess.then(img =>{
//save to db
})
})
Now In Your case best possible, I prefer is to use aync/await Async/await MDN. Do not take it as another way to do it, It is just modern way to use promise. As internally await also setup promise chain. You have both options, either you can go it through promises you will get handy to the one of the best thing of javascript or If you want small piece of code go with await.
router.post('/img2text', upload.single('photo'), async(req, res) => { // To use await function need to be a async function
// Create the object for insertion into database
const Img2text = new img2text({
imgPath: req.file.path,
sender: req.body.sender,
processed: 0,
resultText: "no result",
});
/////////////////////////////////////////////////////////////start
var exec = require("child_process").exec;
await exec(`python uploads/hello.py ${req.file.path}`,(error, stdout, stderr) => {
if (error) {
Img2text.processed=0;
Img2text.resultText='no result'
console.error(`exec error: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
Img2text.processed=1;
Img2text.resultText=stdout.toString('utf8');
console.log(`stderr: ${stderr}`);
console.log(req.query.firstname);
});
/////////////////////////////////////////////////////////end
// Save into database
Img2text.save((err) => {
// Check if error
if (err) {
res.json({ success: false, message: err });
} else {
console.log("img saved !!")
res.json({ success: true, message:img.resultText }); // Return success message
}
});
});