mirror of
https://github.com/bvanroll/rpiRadio.git
synced 2025-08-30 12:32:47 +00:00
Initial Commit
This commit is contained in:
9
ProjectNow/NodeServer/node_modules/python-shell/.jshintrc
generated
vendored
Executable file
9
ProjectNow/NodeServer/node_modules/python-shell/.jshintrc
generated
vendored
Executable file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"predef": [],
|
||||
"browser": false,
|
||||
"node": true,
|
||||
"curly": false,
|
||||
"strict": false,
|
||||
"expr": true,
|
||||
"unused": "vars"
|
||||
}
|
10
ProjectNow/NodeServer/node_modules/python-shell/CHANGELOG.md
generated
vendored
Executable file
10
ProjectNow/NodeServer/node_modules/python-shell/CHANGELOG.md
generated
vendored
Executable file
@@ -0,0 +1,10 @@
|
||||
## 0.0.3
|
||||
* fixed buffering in `PythonShell.receive`, fixing [#1](https://github.com/extrabacon/python-shell/issues/1)
|
||||
|
||||
## 0.0.2
|
||||
* improved documentation
|
||||
|
||||
## 0.0.1
|
||||
* initial version
|
||||
* independent module moved from [extrabacon/pyspreadsheet](https://github.com/extrabacon/pyspreadsheet)
|
||||
|
268
ProjectNow/NodeServer/node_modules/python-shell/README.md
generated
vendored
Executable file
268
ProjectNow/NodeServer/node_modules/python-shell/README.md
generated
vendored
Executable file
@@ -0,0 +1,268 @@
|
||||
# python-shell
|
||||
|
||||
A simple way to run Python scripts from Node.js with basic but efficient inter-process communication and better error handling.
|
||||
|
||||
## Features
|
||||
|
||||
+ 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,code,signal) {
|
||||
if (err) throw err;
|
||||
console.log('The exit code was: ' + code);
|
||||
console.log('The exit signal was: ' + signal);
|
||||
console.log('finished');
|
||||
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 <module>
|
||||
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 <module>\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.<anonymous> (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 <module>
|
||||
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.
|
||||
|
||||
#### `.terminate(signal)`
|
||||
|
||||
Terminates the python script, the optional end callback is invoked if specified. A kill signal may be provided by `signal`, if `signal` is not specified SIGTERM is sent.
|
||||
|
||||
#### 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
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Nicolas Mercier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
259
ProjectNow/NodeServer/node_modules/python-shell/index.js
generated
vendored
Executable file
259
ProjectNow/NodeServer/node_modules/python-shell/index.js
generated
vendored
Executable file
@@ -0,0 +1,259 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var path = require('path');
|
||||
var util = require('util');
|
||||
var spawn = require('child_process').spawn;
|
||||
|
||||
function toArray(source) {
|
||||
if (typeof source === 'undefined' || source === null) {
|
||||
return [];
|
||||
} else if (!Array.isArray(source)) {
|
||||
return [source];
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
function extend(obj) {
|
||||
Array.prototype.slice.call(arguments, 1).forEach(function (source) {
|
||||
if (source) {
|
||||
for (var key in source) {
|
||||
obj[key] = source[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* An interactive Python shell exchanging data through stdio
|
||||
* @param {string} script The python script to execute
|
||||
* @param {object} [options] The launch options (also passed to child_process.spawn)
|
||||
* @constructor
|
||||
*/
|
||||
var PythonShell = function (script, options) {
|
||||
|
||||
function resolve(type, val) {
|
||||
if (typeof val === 'string') {
|
||||
// use a built-in function using its name
|
||||
return PythonShell[type][val];
|
||||
} else if (typeof val === 'function') {
|
||||
// use a custom function
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var errorData = '';
|
||||
EventEmitter.call(this);
|
||||
|
||||
options = extend({}, PythonShell.defaultOptions, options);
|
||||
var pythonPath = options.pythonPath || 'python';
|
||||
var pythonOptions = toArray(options.pythonOptions);
|
||||
var scriptArgs = toArray(options.args);
|
||||
|
||||
this.script = path.join(options.scriptPath || './', script);
|
||||
this.command = pythonOptions.concat(this.script, scriptArgs);
|
||||
this.mode = options.mode || 'text';
|
||||
this.formatter = resolve('format', options.formatter || this.mode);
|
||||
this.parser = resolve('parse', options.parser || this.mode);
|
||||
this.terminated = false;
|
||||
this.childProcess = spawn(pythonPath, this.command, options);
|
||||
|
||||
['stdout', 'stdin', 'stderr'].forEach(function (name) {
|
||||
self[name] = self.childProcess[name];
|
||||
self.parser && self[name].setEncoding(options.encoding || 'utf8');
|
||||
});
|
||||
|
||||
// parse incoming data on stdout
|
||||
if (this.parser) {
|
||||
this.stdout.on('data', PythonShell.prototype.receive.bind(this));
|
||||
}
|
||||
|
||||
// listen to stderr and emit errors for incoming data
|
||||
this.stderr.on('data', function (data) {
|
||||
errorData += ''+data;
|
||||
});
|
||||
|
||||
this.stderr.on('end', function(){
|
||||
self.stderrHasEnded = true
|
||||
terminateIfNeeded();
|
||||
})
|
||||
|
||||
this.stdout.on('end', function(){
|
||||
self.stdoutHasEnded = true
|
||||
terminateIfNeeded();
|
||||
})
|
||||
|
||||
this.childProcess.on('exit', function (code,signal) {
|
||||
self.exitCode = code;
|
||||
self.exitSignal = signal;
|
||||
terminateIfNeeded();
|
||||
});
|
||||
|
||||
function terminateIfNeeded() {
|
||||
if(!self.stderrHasEnded || !self.stdoutHasEnded || (self.exitCode == null && self.exitSignal == null)) return;
|
||||
|
||||
var err;
|
||||
if (errorData || (self.exitCode && self.exitCode !== 0)) {
|
||||
if (errorData) {
|
||||
err = self.parseError(errorData);
|
||||
} else {
|
||||
err = new Error('process exited with code ' + self.exitCode);
|
||||
}
|
||||
err = extend(err, {
|
||||
executable: pythonPath,
|
||||
options: pythonOptions.length ? pythonOptions : null,
|
||||
script: self.script,
|
||||
args: scriptArgs.length ? scriptArgs : null,
|
||||
exitCode: self.exitCode
|
||||
});
|
||||
// do not emit error if only a callback is used
|
||||
if (self.listeners('error').length || !self._endCallback) {
|
||||
self.emit('error', err);
|
||||
}
|
||||
}
|
||||
|
||||
self.terminated = true;
|
||||
self.emit('close');
|
||||
self._endCallback && self._endCallback(err,self.exitCode,self.exitSignal);
|
||||
};
|
||||
};
|
||||
util.inherits(PythonShell, EventEmitter);
|
||||
|
||||
// allow global overrides for options
|
||||
PythonShell.defaultOptions = {};
|
||||
|
||||
// built-in formatters
|
||||
PythonShell.format = {
|
||||
text: function toText(data) {
|
||||
if (!data) return '';
|
||||
else if (typeof data !== 'string') return data.toString();
|
||||
return data;
|
||||
},
|
||||
json: function toJson(data) {
|
||||
return JSON.stringify(data);
|
||||
}
|
||||
};
|
||||
|
||||
// built-in parsers
|
||||
PythonShell.parse = {
|
||||
text: function asText(data) {
|
||||
return data;
|
||||
},
|
||||
json: function asJson(data) {
|
||||
return JSON.parse(data);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Runs a Python script and returns collected messages
|
||||
* @param {string} script The script to execute
|
||||
* @param {Object} options The execution options
|
||||
* @param {Function} callback The callback function to invoke with the script results
|
||||
* @return {PythonShell} The PythonShell instance
|
||||
*/
|
||||
PythonShell.run = function (script, options, callback) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = null;
|
||||
}
|
||||
|
||||
var pyshell = new PythonShell(script, options);
|
||||
var output = [];
|
||||
|
||||
return pyshell.on('message', function (message) {
|
||||
output.push(message);
|
||||
}).end(function (err) {
|
||||
if (err) return callback(err);
|
||||
return callback(null, output.length ? output : null);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses an error thrown from the Python process through stderr
|
||||
* @param {string|Buffer} data The stderr contents to parse
|
||||
* @return {Error} The parsed error with extended stack trace when traceback is available
|
||||
*/
|
||||
PythonShell.prototype.parseError = function (data) {
|
||||
var text = ''+data;
|
||||
var error;
|
||||
|
||||
if (/^Traceback/.test(text)) {
|
||||
// traceback data is available
|
||||
var lines = (''+data).trim().split(/\n/g);
|
||||
var exception = lines.pop();
|
||||
error = new Error(exception);
|
||||
error.traceback = data;
|
||||
// extend stack trace
|
||||
error.stack += '\n ----- Python Traceback -----\n ';
|
||||
error.stack += lines.slice(1).join('\n ');
|
||||
} else {
|
||||
// otherwise, create a simpler error with stderr contents
|
||||
error = new Error(text);
|
||||
}
|
||||
|
||||
return error;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a message to the Python shell through stdin
|
||||
* Override this method to format data to be sent to the Python process
|
||||
* @param {string|Object} data The message to send
|
||||
* @returns {PythonShell} The same instance for chaining calls
|
||||
*/
|
||||
PythonShell.prototype.send = function (message) {
|
||||
var data = this.formatter ? this.formatter(message) : message;
|
||||
if (this.mode !== 'binary') data += '\n';
|
||||
this.stdin.write(data);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses data received from the Python shell stdout stream and emits "message" events
|
||||
* This method is not used in binary mode
|
||||
* Override this method to parse incoming data from the Python process into messages
|
||||
* @param {string|Buffer} data The data to parse into messages
|
||||
*/
|
||||
PythonShell.prototype.receive = function (data) {
|
||||
var self = this;
|
||||
var parts = (''+data).split(/\n/g);
|
||||
|
||||
if (parts.length === 1) {
|
||||
// an incomplete record, keep buffering
|
||||
this._remaining = (this._remaining || '') + parts[0];
|
||||
return this;
|
||||
}
|
||||
|
||||
var lastLine = parts.pop();
|
||||
// fix the first line with the remaining from the previous iteration of 'receive'
|
||||
parts[0] = (this._remaining || '') + parts[0];
|
||||
// keep the remaining for the next iteration of 'receive'
|
||||
this._remaining = lastLine;
|
||||
|
||||
parts.forEach(function (part) {
|
||||
self.emit('message', self.parser(part));
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Closes the stdin stream, which should cause the process to finish its work and close
|
||||
* @returns {PythonShell} The same instance for chaining calls
|
||||
*/
|
||||
PythonShell.prototype.end = function (callback) {
|
||||
this.childProcess.stdin.end();
|
||||
this._endCallback = callback;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Closes the stdin stream, which should cause the process to finish its work and close
|
||||
* @returns {PythonShell} The same instance for chaining calls
|
||||
*/
|
||||
PythonShell.prototype.terminate = function (signal) {
|
||||
this.childProcess.kill(signal);
|
||||
this.terminated = true;
|
||||
return this;
|
||||
};
|
||||
|
||||
module.exports = PythonShell;
|
58
ProjectNow/NodeServer/node_modules/python-shell/package.json
generated
vendored
Executable file
58
ProjectNow/NodeServer/node_modules/python-shell/package.json
generated
vendored
Executable file
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"_from": "python-shell",
|
||||
"_id": "python-shell@0.5.0",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-+jgmFZvwk1yMBBDisDlkXXMYv1eEJKbGCtwHLppGIyEV83cKeX9hjOjfR2yONWK3yQFhum0M2r7UE0U//hiK9w==",
|
||||
"_location": "/python-shell",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "tag",
|
||||
"registry": true,
|
||||
"raw": "python-shell",
|
||||
"name": "python-shell",
|
||||
"escapedName": "python-shell",
|
||||
"rawSpec": "",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "latest"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"#USER",
|
||||
"/"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/python-shell/-/python-shell-0.5.0.tgz",
|
||||
"_shasum": "461983bafd092010bc2760c365b13e7d50aab231",
|
||||
"_spec": "python-shell",
|
||||
"_where": "/home/beppe/Documents/Python/proj/1718PROJrpiRadio/NodeServer",
|
||||
"author": {
|
||||
"name": "Nicolas Mercier",
|
||||
"email": "nicolas@extrabacon.net"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "http://github.com/extrabacon/python-shell/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"dependencies": {},
|
||||
"deprecated": false,
|
||||
"description": "Run Python scripts from Node.js with simple (but efficient) inter-process communication through stdio",
|
||||
"devDependencies": {
|
||||
"mocha": "^2.2.5",
|
||||
"should": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
},
|
||||
"homepage": "http://github.com/extrabacon/python-shell",
|
||||
"keywords": [
|
||||
"python"
|
||||
],
|
||||
"license": "MIT",
|
||||
"name": "python-shell",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+ssh://git@github.com/extrabacon/python-shell.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha -R spec"
|
||||
},
|
||||
"version": "0.5.0"
|
||||
}
|
9
ProjectNow/NodeServer/node_modules/python-shell/test/.jshintrc
generated
vendored
Executable file
9
ProjectNow/NodeServer/node_modules/python-shell/test/.jshintrc
generated
vendored
Executable file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"predef": ["describe", "it", "before", "after", "beforeEach", "afterEach"],
|
||||
"browser": false,
|
||||
"node": true,
|
||||
"curly": false,
|
||||
"strict": false,
|
||||
"expr": true,
|
||||
"unused": "vars"
|
||||
}
|
5
ProjectNow/NodeServer/node_modules/python-shell/test/python/echo_args.py
generated
vendored
Executable file
5
ProjectNow/NodeServer/node_modules/python-shell/test/python/echo_args.py
generated
vendored
Executable file
@@ -0,0 +1,5 @@
|
||||
import sys
|
||||
|
||||
# simple argument echo script
|
||||
for v in sys.argv[1:]:
|
||||
print v
|
4
ProjectNow/NodeServer/node_modules/python-shell/test/python/echo_binary.py
generated
vendored
Executable file
4
ProjectNow/NodeServer/node_modules/python-shell/test/python/echo_binary.py
generated
vendored
Executable file
@@ -0,0 +1,4 @@
|
||||
import sys
|
||||
|
||||
# simple binary echo script
|
||||
sys.stdout.write(sys.stdin.read())
|
5
ProjectNow/NodeServer/node_modules/python-shell/test/python/echo_json.py
generated
vendored
Executable file
5
ProjectNow/NodeServer/node_modules/python-shell/test/python/echo_json.py
generated
vendored
Executable file
@@ -0,0 +1,5 @@
|
||||
import sys, json
|
||||
|
||||
# simple JSON echo script
|
||||
for line in sys.stdin:
|
||||
print json.dumps(json.loads(line))
|
5
ProjectNow/NodeServer/node_modules/python-shell/test/python/echo_text.py
generated
vendored
Executable file
5
ProjectNow/NodeServer/node_modules/python-shell/test/python/echo_text.py
generated
vendored
Executable file
@@ -0,0 +1,5 @@
|
||||
import sys, json
|
||||
|
||||
# simple JSON echo script
|
||||
for line in sys.stdin:
|
||||
print line[:-1]
|
6
ProjectNow/NodeServer/node_modules/python-shell/test/python/error.py
generated
vendored
Executable file
6
ProjectNow/NodeServer/node_modules/python-shell/test/python/error.py
generated
vendored
Executable file
@@ -0,0 +1,6 @@
|
||||
# simple error script
|
||||
|
||||
def divide_by_zero():
|
||||
print 1/0
|
||||
|
||||
divide_by_zero()
|
3
ProjectNow/NodeServer/node_modules/python-shell/test/python/exit-code.py
generated
vendored
Executable file
3
ProjectNow/NodeServer/node_modules/python-shell/test/python/exit-code.py
generated
vendored
Executable file
@@ -0,0 +1,3 @@
|
||||
import sys
|
||||
exit_code = int(sys.argv[1]) if len(sys.argv) > 1 else 0
|
||||
sys.exit(exit_code)
|
3
ProjectNow/NodeServer/node_modules/python-shell/test/python/infinite_loop.py
generated
vendored
Executable file
3
ProjectNow/NodeServer/node_modules/python-shell/test/python/infinite_loop.py
generated
vendored
Executable file
@@ -0,0 +1,3 @@
|
||||
a = 0
|
||||
while(True):
|
||||
a += 1
|
320
ProjectNow/NodeServer/node_modules/python-shell/test/test-python-shell.js
generated
vendored
Executable file
320
ProjectNow/NodeServer/node_modules/python-shell/test/test-python-shell.js
generated
vendored
Executable file
@@ -0,0 +1,320 @@
|
||||
var should = require('should');
|
||||
var PythonShell = require('..');
|
||||
|
||||
describe('PythonShell', function () {
|
||||
|
||||
PythonShell.defaultOptions = {
|
||||
scriptPath: './test/python'
|
||||
};
|
||||
|
||||
describe('#ctor(script, options)', function () {
|
||||
it('should spawn a Python process', function (done) {
|
||||
var pyshell = new PythonShell('exit-code.py');
|
||||
pyshell.command.should.eql(['test/python/exit-code.py']);
|
||||
pyshell.terminated.should.be.false;
|
||||
pyshell.end(function (err) {
|
||||
if (err) return done(err);
|
||||
pyshell.terminated.should.be.true;
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should spawn a Python process with options', function (done) {
|
||||
var pyshell = new PythonShell('exit-code.py', {
|
||||
pythonOptions: '-u'
|
||||
});
|
||||
pyshell.command.should.eql(['-u', 'test/python/exit-code.py']);
|
||||
pyshell.end(done);
|
||||
});
|
||||
it('should spawn a Python process with script arguments', function (done) {
|
||||
var pyshell = new PythonShell('echo_args.py', {
|
||||
args: ['hello', 'world']
|
||||
});
|
||||
pyshell.command.should.eql(['test/python/echo_args.py', 'hello', 'world']);
|
||||
pyshell.end(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#run(script, options)', function () {
|
||||
it('should run the script and return output data', function (done) {
|
||||
PythonShell.run('echo_args.py', {
|
||||
args: ['hello', 'world']
|
||||
}, function (err, results) {
|
||||
if (err) return done(err);
|
||||
results.should.be.an.Array.and.have.lengthOf(2);
|
||||
results.should.eql(['hello', 'world']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should try to run the script and fail appropriately', function (done) {
|
||||
PythonShell.run('unknown_script.py', function (err, results) {
|
||||
err.should.be.an.Error;
|
||||
err.exitCode.should.be.exactly(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should run the script and fail with an extended stack trace', function (done) {
|
||||
PythonShell.run('error.py', function (err, results) {
|
||||
err.should.be.an.Error;
|
||||
err.exitCode.should.be.exactly(1);
|
||||
err.stack.should.containEql('----- Python Traceback -----');
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should run multiple scripts and fail with an extended stack trace for each of them', function (done) {
|
||||
var numberOfTimesToRun = 20;
|
||||
for (var i = 0; i < numberOfTimesToRun; i++) {
|
||||
runSingleErrorScript(end);
|
||||
}
|
||||
var count = 0;
|
||||
function end() {
|
||||
count++;
|
||||
if (count === numberOfTimesToRun) {
|
||||
done();
|
||||
}
|
||||
}
|
||||
function runSingleErrorScript(callback) {
|
||||
PythonShell.run('error.py', function (err, results) {
|
||||
err.should.be.an.Error;
|
||||
err.exitCode.should.be.exactly(1);
|
||||
err.stack.should.containEql('----- Python Traceback -----');
|
||||
callback();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('should run multiple scripts and return output data for each of them', function (done) {
|
||||
var numberOfTimesToRun = 20;
|
||||
for (var i = 0; i < numberOfTimesToRun; i++) {
|
||||
runSingleScript(end);
|
||||
}
|
||||
var count = 0;
|
||||
function end() {
|
||||
count++;
|
||||
if (count === numberOfTimesToRun) {
|
||||
done();
|
||||
}
|
||||
}
|
||||
function runSingleScript(callback) {
|
||||
PythonShell.run('echo_args.py', {
|
||||
args: ['hello', 'world']
|
||||
}, function (err, results) {
|
||||
if (err) return done(err);
|
||||
results.should.be.an.Array.and.have.lengthOf(2);
|
||||
results.should.eql(['hello', 'world']);
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('.send(message)', function () {
|
||||
it('should send string messages when mode is "text"', function (done) {
|
||||
var pyshell = new PythonShell('echo_text.py', {
|
||||
mode: 'text'
|
||||
});
|
||||
var output = '';
|
||||
pyshell.stdout.on('data', function (data) {
|
||||
output += ''+data;
|
||||
});
|
||||
pyshell.send('hello').send('world').end(function (err) {
|
||||
if (err) return done(err);
|
||||
output.should.be.exactly('hello\nworld\n');
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should send JSON messages when mode is "json"', function (done) {
|
||||
var pyshell = new PythonShell('echo_json.py', {
|
||||
mode: 'json'
|
||||
});
|
||||
var output = '';
|
||||
pyshell.stdout.on('data', function (data) {
|
||||
output += ''+data;
|
||||
});
|
||||
pyshell.send({ a: 'b' }).send(null).send([1, 2, 3]).end(function (err) {
|
||||
if (err) return done(err);
|
||||
output.should.be.exactly('{"a": "b"}\nnull\n[1, 2, 3]\n');
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should use a custom formatter', function (done) {
|
||||
var pyshell = new PythonShell('echo_text.py', {
|
||||
formatter: function (message) {
|
||||
return message.toUpperCase();
|
||||
}
|
||||
});
|
||||
var output = '';
|
||||
pyshell.stdout.on('data', function (data) {
|
||||
output += ''+data;
|
||||
});
|
||||
pyshell.send('hello').send('world').end(function (err) {
|
||||
if (err) return done(err);
|
||||
output.should.be.exactly('HELLO\nWORLD\n');
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should write as-is when mode is "binary"', function (done) {
|
||||
var pyshell = new PythonShell('echo_binary.py', {
|
||||
mode: 'binary'
|
||||
});
|
||||
var output = '';
|
||||
pyshell.stdout.on('data', function (data) {
|
||||
output += ''+data;
|
||||
});
|
||||
pyshell.send(new Buffer('i am not a string')).end(function (err) {
|
||||
if (err) return done(err);
|
||||
output.should.be.exactly('i am not a string');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.receive(data)', function () {
|
||||
it('should emit messages as strings when mode is "text"', function (done) {
|
||||
var pyshell = new PythonShell('echo_text.py', {
|
||||
mode: 'text'
|
||||
});
|
||||
var count = 0;
|
||||
pyshell.on('message', function (message) {
|
||||
count === 0 && message.should.be.exactly('hello');
|
||||
count === 1 && message.should.be.exactly('world');
|
||||
count++;
|
||||
}).on('close', function () {
|
||||
count.should.be.exactly(2);
|
||||
}).send('hello').send('world').end(done);
|
||||
});
|
||||
it('should emit messages as JSON when mode is "json"', function (done) {
|
||||
var pyshell = new PythonShell('echo_json.py', {
|
||||
mode: 'json'
|
||||
});
|
||||
var count = 0;
|
||||
pyshell.send({ a: 'b' }).send(null).send([1, 2, 3, 4, 5]);
|
||||
pyshell.on('message', function (message) {
|
||||
count === 0 && message.should.eql({ a: 'b' });
|
||||
count === 1 && should(message).eql(null);
|
||||
count === 2 && message.should.eql([1, 2, 3, 4, 5]);
|
||||
count++;
|
||||
}).on('close', function () {
|
||||
count.should.be.exactly(3);
|
||||
}).end(done);
|
||||
});
|
||||
it('should properly buffer partial messages', function (done) {
|
||||
var pyshell = new PythonShell('echo_json.py', {
|
||||
mode: 'json'
|
||||
});
|
||||
pyshell.on('message', function (message) {
|
||||
message.should.be.an.Object;
|
||||
message.should.eql({ a: true });
|
||||
}).receive('{"a"').receive(':').receive('true}\n').end(done);
|
||||
});
|
||||
it('should not be invoked when mode is "binary"', function (done) {
|
||||
var pyshell = new PythonShell('echo_args.py', {
|
||||
args: ['hello', 'world'],
|
||||
mode: 'binary'
|
||||
});
|
||||
pyshell.receive = function () {
|
||||
throw new Error('should not emit messages in binary mode');
|
||||
};
|
||||
pyshell.end(done);
|
||||
});
|
||||
it('should use a custom parser function', function (done) {
|
||||
var pyshell = new PythonShell('echo_text.py', {
|
||||
mode: 'text',
|
||||
parser: function (message) {
|
||||
return message.toUpperCase();
|
||||
}
|
||||
});
|
||||
var count = 0;
|
||||
pyshell.on('message', function (message) {
|
||||
count === 0 && message.should.be.exactly('HELLO');
|
||||
count === 1 && message.should.be.exactly('WORLD!');
|
||||
count++;
|
||||
}).on('close', function () {
|
||||
count.should.be.exactly(2);
|
||||
}).send('hello').send('world!').end(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.end(callback)', function () {
|
||||
it('should end normally when exit code is zero', function (done) {
|
||||
var pyshell = new PythonShell('exit-code.py');
|
||||
pyshell.end(function (err,code,signal) {
|
||||
if (err) return done(err);
|
||||
code.should.be.exactly(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should emit error if exit code is not zero', function (done) {
|
||||
var pyshell = new PythonShell('exit-code.py', {
|
||||
args: 3
|
||||
});
|
||||
pyshell.on('error', function (err) {
|
||||
err.should.have.properties({
|
||||
message: 'process exited with code 3',
|
||||
exitCode: 3
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should emit error when data is written to stderr', function (done) {
|
||||
var pyshell = new PythonShell('error.py');
|
||||
pyshell.on('error', function (err) {
|
||||
err.message.should.be.exactly('ZeroDivisionError: integer division or modulo by zero');
|
||||
err.should.have.property('traceback');
|
||||
err.traceback.should.containEql('Traceback (most recent call last)');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.parseError(data)', function () {
|
||||
it('should extend error with context properties', function (done) {
|
||||
var pyshell = new PythonShell('exit-code.py', {
|
||||
args: 1
|
||||
});
|
||||
pyshell.on('error', function (err) {
|
||||
err.should.have.properties(['exitCode', 'script', 'options', 'args']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should extend err.stack with traceback', function (done) {
|
||||
var pyshell = new PythonShell('error.py');
|
||||
pyshell.on('error', function (err) {
|
||||
err.stack.should.containEql('----- Python Traceback -----');
|
||||
err.stack.should.containEql('File "test/python/error.py", line 6');
|
||||
err.stack.should.containEql('File "test/python/error.py", line 4');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.terminate()', function () {
|
||||
it('set terminated to true', function (done) {
|
||||
var pyshell = new PythonShell('infinite_loop.py');
|
||||
pyshell.terminate();
|
||||
pyshell.terminated.should.be.true
|
||||
done();
|
||||
});
|
||||
it('run the end callback if specified', function (done) {
|
||||
var pyshell = new PythonShell('infinite_loop.py');
|
||||
var endCalled = false;
|
||||
pyshell.end(()=>{
|
||||
endCalled = true;
|
||||
})
|
||||
pyshell.terminate();
|
||||
pyshell.terminated.should.be.true
|
||||
done();
|
||||
});
|
||||
it('terminate with correct kill signal', function (done) {
|
||||
var pyshell = new PythonShell('infinite_loop.py');
|
||||
var endCalled = false;
|
||||
pyshell.end(()=>{
|
||||
endCalled = true;
|
||||
})
|
||||
pyshell.terminate('SIGKILL');
|
||||
pyshell.terminated.should.be.true;
|
||||
setTimeout(()=>{pyshell.exitSignal.should.be.exactly('SIGKILL');},500);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user