bidirectional communication with python-shell and node.js - javascript

I'm trying to communicate between node.js and python-shell. I was able to recieve data from python-shell-object but when I try to send a message to the python-shell it crashes.
my app.js:
var PythonShell = require('python-shell');
var options = {
scriptPath: '/home/pi/python'
};
var pyshell = new PythonShell('test.py', options, {
mode: 'text'
});
pyshell.stdout.on('data', function(data) {
pyshell.send('go');
console.log(data);
});
pyshell.stdout.on('data2', function(data) {
pyshell.send('OK');
console.log(data);
});
pyshell.end(function(err) {
if (err) throw err;
console.log('End Script');
});
and my test.py:
import sys
print "data"
for line in sys.stdin:
print "data2"
I basically want to have communication in a chronolical way:
recieve "data" from python
send "go" to python
recieve "data2" from python
Another Question:
In the tutorial on https://github.com/extrabacon/python-shell it is written that you have to write pyshell.on() to wait for data while in the source-code the author writes pyshell.stdout.on(). Why is that?
Thanks!!!
(wrong indention in python corrected)

Your code exhibits some incorrect use of python-shell. Here below I have put together some notes. However, this is just what I primarily spot as mistakes so it will just rectify the use of the python-shell library but it might not necessarily remove all issues with your Python counterpart.
Incorrect use of stdout.on('data')
You appear to incorrectly utilize the event handler stdout.on. The handler takes "data" as argument denotes the event which happens when an output message is printed from Python script. This always be stdout.on('data') regardless what messages are printed.
This one is not valid:
pyshell.stdout.on('data2', function(data) { .... })
It should always be
pyshell.stdout.on('data', function(data) { .... })
When relay a message to Python, you should enclose the command with end
You should change from:
pyshell.send('OK');
To this:
pyshell.send('OK').end(function(err){
if (err) handleError(err);
else doWhatever();
})
Therefore, rectifying those two mistakes, you code should become:
pyshell.stdout.on('data', function(data) {
if (data == 'data')
pyshell.send('go').end(fucntion(err){
if (err) console.error(err);
// ...
});
else if (data == 'data2')
pyshell.send('OK').end(function(err){
if (err) console.error(err);
// ...
});
console.log(data);
});

Related

Using child process output globally

For a project I need to incorporate a backend Python function with Javascript (main code for a chatbot). Using Child processes, it seems to work (when using 'node script.js'). However, I need to access the data from the called python function. Right now, all I am getting is the the output.I tried to store it in the global variable, but it's showing as 'undefined'. Is there a way to actually access the data so I can use it outside the stdout.on?
This is the Javascript code for running the pythonscript:
// Give a path to the QR scanner Python file
const qrScannerPath = "python/qrCodeScanner.py"
const base64Arg = "base64_2.txt"
// Provide the '.exe' python file. If python is available as an 'environment varaible', then simply refer to it as 'python'"
const pythonExe = "python"
// Function to convert a utf-8 array to a string
const utfConverter = function (data) {
return String.fromCharCode.apply(String,(data))
}
// let's us handle python scripts
const spawn = require("child_process").spawn
const scriptExe = spawn(pythonExe, [qrScannerPath, base64Arg])
// If all goes well, the program should execute the Python code
let counterpartyData = {}
scriptExe.stdout.on("data", function (data) {
console.log("getting the Python script data...")
let cp = JSON.parse(utfConverter(data))
counterpartyData = {... cp} //should store the data to the variable
});
console.log(counterpartyData) // shows 'undefinied"
// In case our python script cannot be run, we'll get an error
scriptExe.stderr.on("data", (data) => {
console.error("error : " + data.toString())
});
//logs error message
scriptExe.on('error', (error) => {
console.error('error: ', error.message);
});
// Logs a message saying that our code worked perfectly fine
scriptExe.on("exit", (code) => {
console.log("Process quit with code : " + code)
})
If I run this code with node, the output of 'counterpartyData' is undefined. However, inside the stdout, it actually prints out the data I want.
Furthermore, I get python import errors when running the app on Heroku :(.
Thank you in advance!!
Happy New Year and joyful greetings <3

NodeJS Undefined JSON object

just posting a question as I have seen some other similar questions on here but none with a method that seemingly works for me.
I'm new to NodeJS and playing around with requesting data from an API. For my test here im just trying to pull ticker prices based on the input of a prompt from the user.
This works fine, however the object
This is the code I am using to try and make this work:
prompt.start();
prompt.get(['coin'], function (err, result) {
request({url: `https://min-api.cryptocompare.com/data/price?fsym=${result.coin}&tsyms=BTC,USD`, json:true}, function(err, res, json) {
if (err) {
throw err;
}
console.log(json);
var json = JSON.stringify(json);
var string2 = JSON.parse(json);
console.log(string2.btc_price);
console.log(json);
});
console.log('Retrieving: ' + result.coin);
});
The API request works, however it returns JSON that looks like this with my 3 console logs:
{ set_attributes: { btc_price: 1, usd_price: 15839.35 } }
undefined
{"set_attributes":{"btc_price":1,"usd_price":15839.35}} -- (Stringify'd response)
I want to be able to extract the btc_price & usd_price as variables, ive tried a few different methods and can't figure out where exactly im going wrong. Any help would be greatly appreciated!
Cheers,
J
When you attempt to extract the btc_price attribute, it's actually nested so your second console should read console.log(string2.set_attributes.btc_price);
axios has more stars on Github, more followers on Github and more forks.
Features
Make XMLHttpRequests from the browser
Make http requests from node.js
Supports the Promise API
Intercept request and response
Transform request and response data
Cancel requests
Automatic transforms for JSON data
Client side support for protecting against XSRF
Using async / await
// Make a request for a user with a given ID
var preload = null;
async function getPrice(symbol) {
preload = await axios.get('https://min-api.cryptocompare.com/data/price?fsym=${symbol}&tsyms=BTC,USD')
.then(function (response) {
preload = response.data;
})
.catch(function (error) {
console.log(error);
});
return `preload.BTC = ${preload.BTC}; preload.BTC = ${preload.BTC}`;
};
getPrice('ETH');
// return preload.BTC = 0.04689; preload.USD = 742.85

How to obtain a more specific error message when using node.js spawn?

Right now I have the following code to spawn a python script in node.js:
logger.info('Spawning python process');
let proc1 = spawn('python3',
['experimental/paraphrase/paraphrase_detect.py',
results[0].answer, request.query.response]);
proc1.stdout.on('data', (data) => {
logger.info('Python script returned data');
let retVal;
if (data) {
logger.info(data.toString());
retVal = JSON.parse(data.toString());
}
return response.json({data: retVal});
});
proc1.on('close', (code, test) => {
if (code === 1) {
const msg = 'Python exited with exit code 1 meaning there was a ' +
'problem executing the script.';
logger.error(msg);
logger.error(test);
}
});
proc1.on('error', (data) => {
logger.error('Error with calling python script');
if (data) {
logger.error(data.toString());
}
});
The issue I'm dealing with is that specific error messages aren't being returned to node, such as permissions issues, a misspelling of the script name or a missing python package. The best I've been able to do so far is catch an exit code of 1 which just indicates generically that there was a problem running the script.
Try proc1.stderr.on("data")
More details.
https://nodejs.org/api/child_process.html#child_process_child_process

replicate pouchDB document with couchDB

I have used pouchDB in one application and now I want to introduce couchDB to sync the document to remote server. Hence i followed this link http://pouchdb.com/getting-started.html i used the below code to replicate the data to couchDB
var db2 = new PouchDB('todos');
var remoteCouch = 'http://localhost:5984/_utils/database.html?couchdb_sample';
db2.changes({
since: 'now',
live: true
}).on('change', showTodos);
sync();
function sync() {
//alert("sync");
//syncDom.setAttribute('data-sync-state', 'syncing');
//var opts = {live: true};
db2.replicate.to(remoteCouch).on('complete', function () {
console.log("done");
}).on('error', function (err) {
console.log(err);
});
function addTodo(text) {
var todo = {
_id: $("#eid").val()+$("#version").val(),
title: text,
name: $("#nameid").val(),
version: $("#version").val(),
completed: false
};
db2.put(todo, function callback(err, result) {
if (!err) {
console.log('Successfully posted a todo!');
}
else{
console.log(err);
}
});}
here the title has an xml string as value. But i am facing below error
SyntaxError: Unexpected token <
at Object.parse (native)
for this line db2.replicate.to(remoteCouch). I manually created a new document in couchDb database and entered the same data it gave no error but when i try replicating it shows syntax error. Can anyone please hint me where I have gone wrong
http://localhost:5984/_utils/database.html?couchdb_sample
Points to a HTML site (copied over from the browsers address bar, right?). Remove the middle part:
http://localhost:5984/couchdb_sample
It look like you have not defined the remote database in the way PouchDb is expecting. You should use the "new PouchDb" call. The second line of your code is:
var remoteCouch = 'http://localhost:5984/_utils/database.html?couchdb_sample';
but I think it should be like this:
var remoteCouch = new PouchDB('http://localhost:5984/couchdb_sample');
I am not clear from your code what the name of the remote database is, but it would not normally end in ".html" as Ingo Radatz pointed out, so I have assumed it is couchdb_sample above. There is more information about replication on the PouchDb site.

Node.js file write in loop fails randomly

Here is my code :
function aCallbackInLoop(dataArray) {
dataArray.forEach(function (item, index) {
fs.appendFile(fileName, JSON.stringify(item) + "\r\n", function (err) {
if (err) {
console.log('Error writing data ' + err);
} else {
console.log('Data written');
}
});
});
}
I get random errors :
Data written
Data written
.
.
Error writing data Error: UNKNOWN, open 'output/mydata.json'
Error writing data Error: UNKNOWN, open 'output/mydata.json'
.
.
Data written
Error writing data Error: UNKNOWN, open 'output/mydata.json'
The function (aCallbackInLoop) is a callback for a web-service request, which returns chunks of data in dataArray. Multiple web-service requests are being made in a loop, so this callback is perhaps being called in parallel. I doubt it's some file lock issue, but I am not sure how to resolve.
PS: I have made sure it's not a data issue (I am logging all items in dataArray)
Edit : Code after trying write stream :
function writeDataToFile(fileName, data) {
try {
var wStream = fs.createWriteStream(fileName);
wStream.write(JSON.stringify(data) + "\r\n");
wStream.end();
} catch (err) {
console.log(err.message);
}
}
function aCallbackInLoop(dataArray){
dataArray.forEach(function(item, index){
writeDataToFile(filename, item); //filename is global var
});
}
As you have observed, multiple appendFile calls are not able to proceed because of the previous appendFile calls. In this particular case, it would be better to create a write stream.
var wstream = fs.createWriteStream(fileName);
dataArray.forEach(function (item) {
wstream.write(JSON.stringify(item + "\r\n");
});
wstream.end();
If you want to know when all the data is written, then you can register a function with the finish event, like this
var wstream = fs.createWriteStream(fileName);
wstream.on("finish", function() {
// Writing to the file is actually complete.
});
dataArray.forEach(function (item) {
wstream.write(JSON.stringify(item + "\r\n");
});
wstream.end();
Try using the synchronous version of appendFile - https://nodejs.org/api/fs.html#fs_fs_appendfilesync_filename_data_options

Categories