How can I integrate python with nodejs - javascript

I want to use python scripts with my Node.JS server, but whenever I run the node server, the python script doesn't run. It starts the server but no python runs. I think it's in this part of the code but I'm not exactly sure.
My index.js:
app.post("/readPython", (request, response) => {
var dataToSend;
const python = spawn('python', ['python/cookie.py'], "Kevin");
python.stdout.on('data', function (data) {
dataToSend = data.toString();
});
python.stderr.on('data', data => {
console.error(`stderr: ${data}`);
});
python.on('exit', (code) => {
console.log(`child process exited with code ${code}, ${dataToSend}`);
response.sendFile(`${__dirname}/html/result.html`);
});
});
My python script:
import sys
print("Hello World!")
sys.stdout.flush()
I don't know exactly what I should expect but whatever it is, the script isn't running. Any help?

the 3rd argument (options) in spawn() should be an object. I am assuming you are trying to send Kevin as argument.
It should be like
const python = spawn('python', ['helloworld.py',"Kevin"]);
python.stdout.on('data', (data)=> {
console.log(data.toString());
});

Related

How to execute a python script via javascript file in an electronjs app?

I am trying to call and execute a python script via the following javascript code in an electronjs app
function getProgramstatus(){
const { exec } = require('child_process');
exec('python python\\getProgramstatus.py', (error, stdout, stderr) => {
});
let jsonData = require('.\\js\\programstatus.json');
let itemData = JSON.stringify(jsonData);
let programstatus = JSON.parse(itemData);
sessionStorage.setItem('programstatus check', programstatus.status);
}
The goal of the python script is to write a value at a json file.
data1={
"status": "12",
"time" : time.ctime(start)
}
json_object = json.dumps( data1, indent = 4)
with open('..\js\programstatus.json', 'w') as outfile:
outfile.write(json_object)
#print("2")
sys.exit("2")
When i execute the python script via terminal it writes at json file, but when i call it from javascript it doen't write at json file. Any ideas;
Try outputting the response for hints, like this:
function getProgramstatus(){
const { exec } = require('child_process');
exec('python python\\getProgramstatus.py', (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
console.error(`stderr: ${stderr}`);
});
let jsonData = require('.\\js\\programstatus.json');
let itemData = JSON.stringify(jsonData);
let programstatus = JSON.parse(itemData);
sessionStorage.setItem('programstatus check', programstatus.status);
}
And please share the output.
Also the code execution continues while getProgramstatus.py is still running, you want to use execSync / move the code below exec inside the callback or create a promise, so that let jsonData = require('.\\js\\programstatus.json'); gets executed when the python script has finished.
I found the answer, why the json file was not written when the python script was called by the application and not by me at the terminal.
The problem is the folder/file location.
It should be relative to the main.js of the electron app.
So I changed the following:
with open('..\js\programstatus.json', 'w') as outfile:
outfile.write(json_object)
To:
with open('.\js\programstatus.json', 'w') as outfile:
outfile.write(json_object)
and work fine.

Is there a way to get 'live' output lines from a python script spawned by child_process.execFile without flushing stdout every time?

I am trying to get the lines a ('never ending') python script puts into stdout. But currently my code would only log something to the console when the python process exits. Is there a way I can get the 'live' output of the python script line by line?
spawn_child.js:
let execFile = require("child_process").execFile;
var child = execFile("python3", ["PATH_TO_FILE"]);
child.stdout.on("data", data=>{
console.log(data.toString());
});
child.stderr.on("data", data=>{
console.log(data.toString());
});
child.on("exit", code=>{
console.log("Child exited with code "+code);
});
The python file:
from time import sleep
while True:
sleep(3)
print("test")
Edit: It works when using a nodejs script instead of a python script
change python script to
import time
import sys
while True:
time.sleep(1)
print("test")
sys.stdout.flush()
and increase the buffer size of the child process
const child = execFile("python", ["./runner.py"], {
detached: true,
maxBuffer: 10 * 1024 * 1024 * 1024
});
or you can do it without the flushing to stdout with python-shell
const { PythonShell } = require('python-shell');
let pyshell = new PythonShell('runner.py');
pyshell.on('message', function (message) {
console.log(message);
});
pyshell.end(function (err, code, signal) {
if (err) throw err;
console.log('The exit code was: ' + code);
console.log('The exit signal was: ' + signal);
console.log('finished');
});
Use spawn instead of execFile, dont forget options shell and stdio.
const spawn = require("child_process").spawn;
const child = spawn("python3", ["file.py"], {shell: true, stdio: 'inherit'});
child.on('data', function(data) {
console.log(data);
});
child.on('close', function(code) {
console.log('Child process exited with exit code '+code);
});
You can also add cwd option.
Was trying to implement something similar inside a NextJS application and wanted live output from my python script and using python-shell had the same issue that it was only giving me output when the process existed and I ended up using node-pty instead which worked as expected:
import { spawn } from "node-pty"
const pyProcess = spawn("python", ["path/to/python/script"], {
name: 'xterm-color',
cols: 80,
rows: 30,
cwd: process.cwd(),
});
pyProcess.on('data', function (data: { toString: () => any; }) {
console.log(data.toString());
});
pyProcess.on('exit', (code: any) => {
console.log(`child process exited with code ${code}`);
});

Why is my asynchronous (NodeJS-Python) WebSocket not connecting immediately?

This is a continuation of a question I had earlier, Using Socket IO and aiohttp for data transfer between node JS and Python, based on this tutorial, https://tutorialedge.net/python/python-socket-io-tutorial/.
I have an asynchronous tunnel that connects a Node JS client (send.js) and a python server (receive.py). Right now send.js outputs a random number and then sends it to the Python server (receive.py), which then sends the message back to the JS client.
The setup works, however, it takes a couple minutes for the server to start receiving data from send.js, and I do not know why.
The Node JS script will output data, but the server will not receive it for at least a couple minutes and even after it starts receiving data, it does not receive the data it did not get earlier, it will only receive the data from the moment the server and client can finally connect.
I am not sure if this has something to with the Python side, Node JS side, or something else.
I am using Node 8.16.1 and Python 3.7.3
The code is below:
send.js
const io = require('socket.io-client');
const socket = io('http://localhost:8080');
socket.on('reply', message => {
console.log('Got from server: ');
console.log(message);
});
function generateNumber() {
const n = Math.floor(Math.random() * 50);
return { number: n };
}
function sendMsg() {
const json = generateNumber();
console.log('Sending to server:');
console.log(json);
socket.emit('message', json);
}
function loop() {
const rand = Math.round(Math.random() * (3000 - 500)) + 500;
setTimeout(() => {
sendMsg();
loop();
}, rand);
}
socket.on('connect', () => {
console.log('Connected to server');
loop();
});
receive.py
from aiohttp import web
import socketio
# creates a new Async Socket IO Server
sio = socketio.AsyncServer()
# Creates a new Aiohttp Web Application
app = web.Application()
# Binds our Socket.IO server to our Web App
# instance
sio.attach(app)
# If we wanted to create a new websocket endpoint,
# use this decorator, passing in the name of the
# event we wish to listen out for
#sio.on('message')
async def print_message(sid, message):
# When we receive a new event of type
# 'message' through a socket.io connection
# we print the socket ID and the message
#print("Socket ID: " , sid)
print(message)
await sio.emit('reply', message)
# We kick off our server
if __name__ == '__main__':
web.run_app(app)
Let me know if more information is needed.
I don't know if you have to use the packages that you are using but here is my working version with ws package for node and asyncio and websockets packages for python. Have fun and nice question.
send.js
const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:8080')
console.log(ws)
function generateNumber() {
const n = Math.floor(Math.random() * 50);
return {
number: n
};
}
function sendMsg() {
const json = JSON.stringify(generateNumber());
console.log('Sending to server:');
console.log(json);
ws.send(json);
}
function loop() {
setTimeout(() => {
sendMsg();
loop();
}, 5000);
}
ws.on('open', function open() {
console.log('connect')
console.log(ws)
loop()
})
ws.on('message', function(data) {
console.log(data)
})
receive.py
import asyncio
import websockets
async def start(websocket, path):
print("connected")
while True:
data = await websocket.recv()
print(f"< {data}")
await websocket.send(data)
async def main():
server = await websockets.serve(start, 'localhost', 8080)
await server.wait_closed()
asyncio.run(main())

How to trigger batch file in node js

I have a batch file which contains many jar files separated by semicolon :
%~d0
cd %~dp0
java -Xms256M -Xmx1024M -cp .;../lib/routines.jar;../lib/accessors-smart-1.1.jar;../lib/advancedPersistentLookupLib-1.0.jar; test_sample_connector.test_connector_0_1.TEST_connector --context=Default %*
When I call this batch in NodeJS I am getting the following error :
SyntaxError: Unexpected token %
But this batch file works fine if I run in command prompt.
Here is my node js code:
const { spawn } = require('child_process');
const bat = spawn('cmd.exe',['/c','../config/TEST_connector_0.1/TEST_connector/TEST_connector_run.bat']);
bat.stdout.on('data', (data) => {
console.log(data.toString());
});
bat.stderr.on('data', (data) => {
console.log(data.toString());
});
bat.on('exit', (code) => {
console.log(`Child exited with code ${code}`);
});

Execute Python script with Node.js

I am trying to execute Python Script when I click on HTML button. Both files are on a Node.js Server. When I press the button I get this message in the browser console:
app.js:5 Uncaught ReferenceError: runPython is not defined
I am not sure how to write my AJAX script to call the runPython() function on my Node web server file. Below is my code:
index.html
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.js"> </script>
</head>
<body>
<button id="myButton">Run Python Script</button>
<script src="app.js"></script>
</body>
</html>
app.js
$('#myButton').click(function() {
$.ajax({
url: "",
success: function(data) {
runPython();
},
});
});
webserver.js (node.js)
'use strict';
const http = require('http');
const url = require('url');
const fs = require('fs');
const path = require('path');
let mimes = {
'.htm': 'text/html',
'.css': 'text/css',
'.js': 'text/javascript'
}
//Have ajax call it to execute Python Script
function runPython(){
let exec = require('child_process').exec;
exec('python myscript.py', (error, stdout, stderr) => {
console.log(stdout);
});
}
function fileAccess(filepath) {
return new Promise((resolve, reject) => {
fs.access(filepath, fs.F_OK, error => {
if(!error) {
resolve(filepath);
} else {
reject(error);
}
});
});
}
function streamFile(filepath) {
return new Promise((resolve, reject) => {
let fileStream = fs.createReadStream(filepath);
fileStream.on('open', () => {
resolve(fileStream);
});
fileStream.on('error', error => {
reject(error);
});
});
}
function webserver(req, res) {
// if the route requested is '/', then load 'index.htm' or else
// load the requested file(s)
let baseURI = url.parse(req.url);
let filepath = __dirname + (baseURI.pathname === '/' ? '/index.htm' : baseURI.pathname);
let contentType = mimes[path.extname(filepath)];
fileAccess(filepath)
.then(streamFile)
.then(fileStream => {
res.writeHead(200, {'Content-type': contentType});
//res.end(content, 'utf-8');
fileStream.pipe(res);
})
.catch(error => {
res.writeHead(404);
res.end(JSON.stringify(error));
});
}
http.createServer(webserver).listen(3000, () => {
console.log('Webserver running on port 3000');
});
How should I write the AJAX code so that the function in webserver.js will run?
The browser is loading the script at that url. This is treated as either data or text. Browsers don't generally run Python so Working As Intended.
You need to make an ajax request to the server that will run some code that will invoke your python script. You're missing the middle part of that process, and simply requesting the contents of myscript.py as text.
Something like:
$('#myButton').click(function() {
$.ajax({
url: "/invoke-script"
});
});
I am not familiar with Node, but I imagine you have some sort of controller and the ability to execute commands (maybe using https://www.npmjs.com/package/exec-sync). In that controller you then invoke your python script and do what you need with the output.
Think about this script like an executable. If your URL points to some *.exe file, clicking on the URL tells the web browser to download the resource. The same happens to Python script.
If you want to run some python code, try to handle HTTP request instead with simple HTTP server. This is the most common way to execute some actions on HTTP request. Check documentation for SimpleHTTPServer and BaseHTTPServer.
Here and here you can find some code snippet for simple server implementation.

Categories