python-shell icon indicating copy to clipboard operation
python-shell copied to clipboard

Promise support

Open damianobarbati opened this issue 7 years ago • 12 comments

Is it possible to have the result of a python script fired as a ES6 Promise?

damianobarbati avatar Mar 12 '17 23:03 damianobarbati

any news on this?

damianobarbati avatar Apr 26 '17 09:04 damianobarbati

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

extrabacon avatar Apr 27 '17 23:04 extrabacon

This feature would be awesome, especially for users working in React, Vue, Angular etc. Any progress or where to start?

maziarz avatar Jan 16 '18 10:01 maziarz

@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');

Almenon avatar Jan 17 '18 02:01 Almenon

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);
  });

wosevision avatar May 01 '18 19:05 wosevision

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 avatar Aug 20 '18 04:08 Almenon

@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 avatar Aug 22 '18 14:08 wosevision

@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 :)

Almenon avatar Aug 24 '18 02:08 Almenon

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))
    )
  );
}

jordond avatar Sep 03 '18 16:09 jordond

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.

Almenon avatar Aug 24 '19 17:08 Almenon

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 avatar Feb 21 '20 10:02 nkhil

@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);
		});
	});
};

AlexString avatar Apr 02 '22 19:04 AlexString

This is done w/ the latest version of python-shell (5.0.0).

Almenon avatar Feb 11 '23 05:02 Almenon