python-shell
python-shell copied to clipboard
Promise support
Is it possible to have the result of a python script fired as a ES6 Promise?
any news on this?
Sorry, you will have to wrap the callbacks with a 3rd party library for now. PRs are welcome though.
See: http://bluebirdjs.com/docs/api/promisification.html
This feature would be awesome, especially for users working in React, Vue, Angular etc. Any progress or where to start?
@maziarz like extrabacon said, you can use bluebird to promisfy stuff.
A good example of this is python-bridge, a very similar project to this one.
Some relevant code from their index.js:
'use strict';
let Promise = require('bluebird');
let path = require('path');
let child_process = Promise.promisifyAll(require('child_process'));
const PYTHON_BRIDGE_SCRIPT = path.join(__dirname, 'node_python_bridge.py');
Even better: if you've updated your Node environment to one of the latest long-term-support (LTS) releases (8.x at the time of writing), then util.promisify
is natively supported – you already have this tool.
From 2ality.com:
const { promisify } = require('util');
const fs = require('fs');
const readFileAsync = promisify(fs.readFile);
const filePath = process.argv[2];
readFileAsync(filePath, {encoding: 'utf8'})
.then((text) => {
console.log('CONTENT:', text);
})
.catch((err) => {
console.log('ERROR:', err);
});
util.promisify sounds cool but we might want to continue supporting node v7 - anyone know when v7 will be deprecated?
It's also possible to create promises manually, but it takes a bit of boilerplate - see my new checkSyntaxCode I added in as an example:
/**
* checks syntax without executing code
* @param {string} filePath
* @returns {Promise} rejects w/ stderr if syntax failure
*/
static async checkSyntaxFile(filePath:string){
let compileCommand = `${this.defaultPythonPath} -m py_compile ${filePath}`
return new Promise((resolve, reject) => {
exec(compileCommand, (error, stdout, stderr) => {
if(error == null) resolve()
else reject(stderr)
})
})
}
@Almenon Node 7.x, along with all odd-numbered releases, are not LTS versions: their support ends as quickly as it comes. Node 8 is the current LTS Node version, so if you have things running 7, then they should already be upgraded to 8 because your support is already up.
The original blog post for the release of 7 states that support would likely end in June 2017; since it's not a LTS version, it isn't included on Node's release schedule / EOL list. For reference, you can see the full schedule by going to the nodejs.org homepage and clicking "Long term support (LTS) schedule".
So in short: it is already deprecated.
@wosevision, ah, that's good news. Thanks for the tip. I have some work in AREPL I need to get done but I can probably get to this after that. I've earmarked the issue for v1.0.1 release :)
Here's a wrapper I use, works well enough for me.
import { resolve } from "path";
import { run } from "python-shell";
export function pythonExec(
pythonScript: string,
args: string[]
): Promise<string[]> {
return new Promise((done, reject) =>
run(
resolve(pythonScript),
{ args, scriptPath: __dirname },
(err, results: string[]) => (err ? reject(err) : done(results))
)
);
}
To be honest I'm probably not going to get to this anytime soon. I'd be happy to review a PR if someone submits it. Or if someone wants to donate to charity I can use that as motivation to get around to implementing this.
We had the same issue today, and ended up promisifying it like so:
function someFunction(date, data){
return new Promise((resolve, reject) => {
let result;
let pyshell = new PythonShell('pyshell_test.py', {mode: 'text', args: [date]});
pyshell.send(JSON.stringify(data['someProperty']));
pyshell.on('message', function (message) {
result = JSON.parse(message);
});
pyshell.on('stderr', function (stderr) {
console.log(stderr);
});
pyshell.end(function (err, code, signal) {
if (err) reject(err);
console.log('The exit code was: ' + code);
console.log('The exit signal was: ' + signal);
console.log('finished');
resolve(result);
});
});
}
@nkhil implementation worked for me but I did something more like this in a Class
:
callPythonScript = () => {
return new Promise((resolve, reject) => {
PythonShell.run(this.pythonScriptName, this.options, (err, result) => {
if (err) reject(err);
resolve(result);
});
});
};
This is done w/ the latest version of python-shell (5.0.0).