From 1d7d3ad92cf4be5b8a82df9ba8ce2eacf89c7b05 Mon Sep 17 00:00:00 2001 From: ClimbsRocks Date: Sun, 18 Oct 2015 21:48:54 -0700 Subject: [PATCH 1/2] avoids unnecessary logging from sknn --- README.md | 236 +-------------------------------------------------- index.js | 6 +- package.json | 8 +- 3 files changed, 12 insertions(+), 238 deletions(-) diff --git a/README.md b/README.md index db96034..7b62d5e 100644 --- a/README.md +++ b/README.md @@ -1,240 +1,10 @@ # python-shell -A simple way to run Python scripts from Node.js with basic but efficient inter-process communication and better error handling. +This is a fork of extrabacon's useful [python-shell](https://github.com/extrabacon/python-shell). +It is very slightly customized to work with ppComplete. -## Features +With any questions, please refer back to extrabacon's [original version](https://github.com/extrabacon/python-shell). -+ Reliably spawn Python scripts in a child process -+ Built-in text, JSON and binary modes -+ Custom parsers and formatters -+ Simple and efficient data transfers through stdin and stdout streams -+ Extended stack traces when an error is thrown - -## Installation - -```bash -npm install python-shell -``` - -To run the tests: -```bash -npm test -``` - -## Documentation - -### Running a Python script: - -```js -var PythonShell = require('python-shell'); - -PythonShell.run('my_script.py', function (err) { - if (err) throw err; - console.log('finished'); -}); -``` - -If the script writes to stderr or exits with a non-zero code, an error will be thrown. - -### Running a Python script with arguments and options: - -```js -var PythonShell = require('python-shell'); - -var options = { - mode: 'text', - pythonPath: 'path/to/python', - pythonOptions: ['-u'], - scriptPath: 'path/to/my/scripts', - args: ['value1', 'value2', 'value3'] -}; - -PythonShell.run('my_script.py', options, function (err, results) { - if (err) throw err; - // results is an array consisting of messages collected during execution - console.log('results: %j', results); -}); -``` - -### Exchanging data between Node and Python: - -```js -var PythonShell = require('python-shell'); -var pyshell = new PythonShell('my_script.py'); - -// sends a message to the Python script via stdin -pyshell.send('hello'); - -pyshell.on('message', function (message) { - // received a message sent from the Python script (a simple "print" statement) - console.log(message); -}); - -// end the input stream and allow the process to exit -pyshell.end(function (err) { - if (err) throw err; - console.log('finished'); -}); -``` - -Use `.send(message)` to send a message to the Python script. Attach the `message` event to listen to messages emitted from the Python script. - -Use `options.mode` to quickly setup how data is sent and received between your Node and Python applications. - - * use `text` mode for exchanging lines of text - * use `json` mode for exchanging JSON fragments - * use `binary` mode for anything else (data is sent and received as-is) - -For more details and examples including Python source code, take a look at the tests. - -### Error Handling and extended stack traces - -An error will be thrown if the process exits with a non-zero exit code or if data has been written to stderr. Additionally, if "stderr" contains a formatted Python traceback, the error is augmented with Python exception details including a concatenated stack trace. - -Sample error with traceback (from test/python/error.py): -``` -Traceback (most recent call last): - File "test/python/error.py", line 6, in - divide_by_zero() - File "test/python/error.py", line 4, in divide_by_zero - print 1/0 -ZeroDivisionError: integer division or modulo by zero -``` -would result into the following error: -```js -{ [Error: ZeroDivisionError: integer division or modulo by zero] - traceback: 'Traceback (most recent call last):\n File "test/python/error.py", line 6, in \n divide_by_zero()\n File "test/python/error.py", line 4, in divide_by_zero\n print 1/0\nZeroDivisionError: integer division or modulo by zero\n', - executable: 'python', - options: null, - script: 'test/python/error.py', - args: null, - exitCode: 1 } -``` -and `err.stack` would look like this: -``` -Error: ZeroDivisionError: integer division or modulo by zero - at PythonShell.parseError (python-shell/index.js:131:17) - at ChildProcess. (python-shell/index.js:67:28) - at ChildProcess.EventEmitter.emit (events.js:98:17) - at Process.ChildProcess._handle.onexit (child_process.js:797:12) - ----- Python Traceback ----- - File "test/python/error.py", line 6, in - divide_by_zero() - File "test/python/error.py", line 4, in divide_by_zero - print 1/0 -``` - -## API Reference - -#### `PythonShell(script, options)` constructor - -Creates an instance of `PythonShell` and starts the Python process - -* `script`: the path of the script to execute -* `options`: the execution options, consisting of: - * `mode`: Configures how data is exchanged when data flows through stdin and stdout. The possible values are: - * `text`: each line of data (ending with "\n") is emitted as a message (default) - * `json`: each line of data (ending with "\n") is parsed as JSON and emitted as a message - * `binary`: data is streamed as-is through `stdout` and `stdin` - * `formatter`: each message to send is transformed using this method, then appended with "\n" - * `parser`: each line of data (ending with "\n") is parsed with this function and its result is emitted as a message - * `encoding`: the text encoding to apply on the child process streams (default: "utf8") - * `pythonPath`: The path where to locate the "python" executable. Default: "python" - * `pythonOptions`: Array of option switches to pass to "python" - * `scriptPath`: The default path where to look for scripts. Default is the current working directory. - * `args`: Array of arguments to pass to the script - -Other options are forwarded to `child_process.spawn`. - -PythonShell instances have the following properties: -* `script`: the path of the script to execute -* `command`: the full command arguments passed to the Python executable -* `stdin`: the Python stdin stream, used to send data to the child process -* `stdout`: the Python stdout stream, used for receiving data from the child process -* `stderr`: the Python stderr stream, used for communicating errors -* `childProcess`: the process instance created via `child_process.spawn` -* `terminated`: boolean indicating whether the process has exited -* `exitCode`: the process exit code, available after the process has ended - -Example: -```js -// create a new instance -var shell = new PythonShell('script.py', options); -``` - -#### `#defaultOptions` - -Configures default options for all new instances of PythonShell. - -Example: -```js -// setup a default "scriptPath" -PythonShell.defaultOptions = { scriptPath: '../scripts' }; -``` - -#### `#run(script, options, callback)` - -Runs the Python script and invokes `callback` with the results. The callback contains the execution error (if any) as well as an array of messages emitted from the Python script. - -This method is also returning the `PythonShell` instance. - -Example: -```js -// run a simple script -PythonShell.run('script.py', function (err, results) { - // script finished -}); -``` - -#### `.send(message)` - -Sends a message to the Python script via stdin. The data is formatted according to the selected mode (text or JSON), or through a custom function when `formatter` is specified. - -Example: -```js -// send a message in text mode -var shell = new PythonShell('script.py', { mode: 'text '}); -shell.send('hello world!'); - -// send a message in JSON mode -var shell = new PythonShell('script.py', { mode: 'json '}); -shell.send({ command: "do_stuff", args: [1, 2, 3] }); -``` - -#### `.receive(data)` - -Parses incoming data from the Python script written via stdout and emits `message` events. This method is called automatically as data is being received from stdout. - -#### `.end(callback)` - -Closes the stdin stream, allowing the Python script to finish and exit. The optional callback is invoked when the process is terminated. - -#### event: `message` - -Fires when a chunk of data is parsed from the stdout stream via the `receive` method. If a `parser` method is specified, the result of this function will be the message value. This event is not emitted in binary mode. - -Example: -```js -// receive a message in text mode -var shell = new PythonShell('script.py', { mode: 'text '}); -shell.on('message', function (message) { - // handle message (a line of text from stdout) -}); - -// receive a message in JSON mode -var shell = new PythonShell('script.py', { mode: 'json '}); -shell.on('message', function (message) { - // handle message (a line of text from stdout, parsed as JSON) -}); -``` - -#### event: `close` - -Fires when the process has been terminated, with an error or not. - -#### event: `error` - -Fires when the process terminates with a non-zero exit code, or if data is written to the stderr stream. ## License diff --git a/index.js b/index.js index a632b6a..e28d3d6 100644 --- a/index.js +++ b/index.js @@ -70,7 +70,11 @@ var PythonShell = function (script, options) { // listen to stderr and emit errors for incoming data this.stderr.on('data', function (data) { - errorData += ''+data; + // sknn gives some unnecessary and distracting warnings that cause python-shell to throw some rather ugly-looking error messages. + // the lines below make sure the user isn't distracted by these harmless but distracting messages + if( data.indexOf('WARNING:sknn:Parameter') === -1) { + errorData += ''+data; + } }); this.childProcess.on('exit', function (code) { diff --git a/package.json b/package.json index d0108f7..753e661 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "python-shell", "version": "0.2.0", - "description": "Run Python scripts from Node.js with simple (but efficient) inter-process communication through stdio", + "description": "slightly customized version of extrabacon's python-shell for ppComplete", "keywords": [ "python" ], @@ -15,10 +15,10 @@ }, "repository": { "type": "git", - "url": "http://github.com/extrabacon/python-shell" + "url": "http://github.com/ClimbsRocks/python-shell" }, - "homepage": "http://github.com/extrabacon/python-shell", - "bugs": "http://github.com/extrabacon/python-shell/issues", + "homepage": "http://github.com/ClimbsRocks/python-shell", + "bugs": "http://github.com/ClimbsRocks/python-shell/issues", "author": { "name": "Nicolas Mercier", "email": "nicolas@extrabacon.net" From 12b9b25952e94ac3cb92b275c4f616f0d3707366 Mon Sep 17 00:00:00 2001 From: ClimbsRocks Date: Sun, 18 Oct 2015 21:50:40 -0700 Subject: [PATCH 2/2] renames to avoid confusion --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 753e661..5c9a743 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,9 @@ { - "name": "python-shell", + "name": "ppc-python-shell", "version": "0.2.0", "description": "slightly customized version of extrabacon's python-shell for ppComplete", "keywords": [ + "ppComplete", "python" ], "scripts": {