diff --git a/index-compiled.js b/index-compiled.js new file mode 100644 index 0000000..199ac8d --- /dev/null +++ b/index-compiled.js @@ -0,0 +1,318 @@ +'use strict'; + +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } + +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } + +function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); } + +function isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } + +function _construct(Parent, args, Class) { if (isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } + +function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; } + +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } + +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } + +var path = require('path'); + +var child_process = require('child_process'); + +var PYTHON_BRIDGE_SCRIPT = path.join(__dirname, 'node_python_bridge.py'); + +function pythonBridge(opts) { + // default options + var intepreter = opts && opts.python || 'python'; + var stdio = opts && opts.stdio || ['pipe', process.stdout, process.stderr]; + var options = { + cwd: opts && opts.cwd, + env: opts && opts.env, + uid: opts && opts.uid, + gid: opts && opts.gid, + stdio: stdio.concat(['ipc']) + }; // create process bridge + + var ps = child_process.spawn(intepreter, [PYTHON_BRIDGE_SCRIPT], options); + var queue = singleQueue(); + + function sendPythonCommand(type, enqueue, self) { + function wrapper() { + self = self || wrapper; + var code = json.apply(this, arguments); + + if (!(this && this.connected || self.connected)) { + return Promise.reject(new PythonBridgeNotConnected()); + } + + return enqueue(function () { + return new Promise(function (resolve, reject) { + ps.send({ + type: type, + code: code + }); + ps.once('message', onMessage); + ps.once('close', onClose); + + function onMessage(data) { + ps.removeListener('close', onClose); + + if (data && data.type && data.type === 'success') { + resolve(eval("(".concat(data.value, ")"))); + } else if (data && data.type && data.type === 'exception') { + reject(new PythonException(data.value)); + } else { + reject(data); + } + } + + function onClose(exit_code, message) { + ps.removeListener('message', onMessage); + + if (!message) { + reject(new Error("Python process closed with exit code ".concat(exit_code))); + } else { + reject(new Error("Python process closed with exit code ".concat(exit_code, " and message: ").concat(message))); + } + } + }); + }); + } + + return wrapper; + } + + function setupLock(enqueue) { + return function (f) { + return enqueue(function () { + var lock_queue = singleQueue(); + var lock_python = sendPythonCommand('evaluate', lock_queue); + lock_python.ex = sendPythonCommand('execute', lock_queue, lock_python); + lock_python.lock = setupLock(lock_queue); + lock_python.connected = true; + lock_python.__proto__ = python; + return f(lock_python); + }); + }; + } // API + + + var python = sendPythonCommand('evaluate', queue); + python.ex = sendPythonCommand('execute', queue, python); + python.lock = setupLock(queue); + python.pid = ps.pid; + python.connected = true; + python.Exception = PythonException; + python.isException = isPythonException; + + python.disconnect = function () { + python.connected = false; + return queue(function () { + ps.disconnect(); + }); + }; + + python.end = python.disconnect; + + python.kill = function (signal) { + python.connected = false; + ps.kill(signal); + }; + + python.stdin = ps.stdin; + python.stdout = ps.stdout; + python.stderr = ps.stderr; + return python; +} + +var PythonException = +/*#__PURE__*/ +function (_Error) { + _inherits(PythonException, _Error); + + function PythonException(exc) { + var _this; + + _classCallCheck(this, PythonException); + + if (exc && exc.format) { + _this = _possibleConstructorReturn(this, _getPrototypeOf(PythonException).call(this, exc.format.join(''))); + } else if (exc && exc.error) { + _this = _possibleConstructorReturn(this, _getPrototypeOf(PythonException).call(this, "Python exception: ".concat(exc.error))); + } else { + _this = _possibleConstructorReturn(this, _getPrototypeOf(PythonException).call(this, 'Unknown Python exception')); + } + + _this.error = exc.error; + _this.exception = exc.exception; + _this.traceback = exc.traceback; + _this.format = exc.format; + return _possibleConstructorReturn(_this); + } + + return PythonException; +}(_wrapNativeSuper(Error)); + +var PythonBridgeNotConnected = +/*#__PURE__*/ +function (_Error2) { + _inherits(PythonBridgeNotConnected, _Error2); + + function PythonBridgeNotConnected() { + _classCallCheck(this, PythonBridgeNotConnected); + + return _possibleConstructorReturn(this, _getPrototypeOf(PythonBridgeNotConnected).call(this, 'Python bridge is no longer connected.')); + } + + return PythonBridgeNotConnected; +}(_wrapNativeSuper(Error)); + +function isPythonException(name, exc) { + var thunk = function thunk(exc) { + return exc instanceof PythonException && exc.exception && exc.exception.type.name === name; + }; + + if (exc === undefined) { + return thunk; + } + + return thunk(exc); +} + +function singleQueue() { + var last = Promise.resolve(); + return function enqueue(f) { + var wait = last; + var done; + last = new Promise(function (resolve) { + done = resolve; + }); + return promiseFinally(new Promise(function (resolve, reject) { + promiseFinally(wait, function () { + promiseTry(f).then(resolve, reject); + }); + }), function () { + return done(); + }); + }; +} + +function dedent(code) { + // dedent text + var lines = code.split('\n'); + var offset = null; // remove extra blank starting line + + if (!lines[0].trim()) { + lines.shift(); + } + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = lines[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var line = _step.value; + var trimmed = line.trimLeft(); + + if (trimmed) { + offset = line.length - trimmed.length + 1; + break; + } + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator["return"] != null) { + _iterator["return"](); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + if (!offset) { + return code; + } + + var match = new RegExp('^' + new Array(offset).join('\\s?')); + return lines.map(function (line) { + return line.replace(match, ''); + }).join('\n'); +} + +function json(text_nodes) { + var values = Array.prototype.slice.call(arguments, 1); + return dedent(text_nodes.reduce(function (cur, acc, i) { + return cur + serializePython(values[i - 1]) + acc; + })); +} + +function serializePython(value) { + if (value === null || typeof value === 'undefined') { + return 'None'; + } else if (value === true) { + return 'True'; + } else if (value === false) { + return 'False'; + } else if (value === Infinity) { + return "float('inf')"; + } else if (value === -Infinity) { + return "float('-inf')"; + } else if (value instanceof Array) { + return "[".concat(value.map(serializePython).join(', '), "]"); + } else if (typeof value === 'number') { + if (isNaN(value)) { + return "float('nan')"; + } + + return JSON.stringify(value); + } else if (typeof value === 'string') { + return JSON.stringify(value); + } else if (value instanceof Map) { + var props = Array.from(value.entries()).map(function (kv) { + return "".concat(serializePython(kv[0]), ": ").concat(serializePython(kv[1])); + }); + return "{".concat(props.join(', '), "}"); + } else { + var _props = Object.keys(value).map(function (k) { + return "".concat(serializePython(k), ": ").concat(serializePython(value[k])); + }); + + return "{".concat(_props.join(', '), "}"); + } +} + +function promiseTry(f) { + return new Promise(function (resolve, reject) { + try { + resolve(f()); + } catch (e) { + reject(e); + } + }); +} + +function promiseFinally(promise, cb) { + promise.then(cb, cb); + return promise; +} + +pythonBridge.pythonBridge = pythonBridge; +pythonBridge.PythonException = PythonException; +pythonBridge.PythonBridgeNotConnected = PythonBridgeNotConnected; +pythonBridge.isPythonException = isPythonException; +pythonBridge.json = json; +pythonBridge.serializePython = serializePython; +module.exports = pythonBridge.pythonBridge = pythonBridge; diff --git a/index.d.ts b/index.d.ts index 126e1f6..5744b40 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,8 +1,6 @@ -interface pythonBridge extends Function { - (options?: PythonBridgeOptions): PythonBridge; -} +type pythonBridge = (options?: PythonBridgeOptions) => PythonBridge; -export const pythonBridge: pythonBridge +export const pythonBridge: pythonBridge; export interface PythonBridgeOptions { python?: string; @@ -14,9 +12,9 @@ export interface PythonBridgeOptions { } export interface PythonBridge { - (literals: TemplateStringsArray | string, ...placeholders: any[]): Bluebird.Promise; - ex(literals: TemplateStringsArray | string, ...placeholders: any[]): Bluebird.Promise; - lock(withLock: (python: PythonBridge) => Promise): Bluebird.Promise + (literals: TemplateStringsArray | string, ...placeholders: any[]): Promise; + ex(literals: TemplateStringsArray | string, ...placeholders: any[]): Promise; + lock(withLock: (python: PythonBridge) => Promise): Promise pid: number; end(): Promise; disconnect(): Promise; @@ -31,29 +29,21 @@ export function isPythonException(name: string): (e: any) => boolean; export function isPythonException(name: string, e: any): boolean; export class PythonException extends Error { - exception: { + public exception: { message: string; args: any[]; type: { name: string; module: string; } format: string[]; }; - traceback: { + public traceback: { lineno: number; strack: string[]; format: string[] }; - format: string[] + public format: string[] } -export type Pipe = "pipe" | "ignore" | "inherit"; +export type Pipe = 'pipe' | 'ignore' | 'inherit'; export type PipeStdin = Pipe | NodeJS.ReadableStream; export type PipeStdout = Pipe | NodeJS.WritableStream; export type PipeStderr = Pipe | NodeJS.WritableStream; - -export namespace Bluebird { - interface Promise extends _Promise { - timeout(milliseconds: number): Bluebird.Promise; - } -} - -type _Promise = Promise; diff --git a/index.js b/index.js index c19811d..fa9f4db 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,7 @@ 'use strict'; -let Promise = require('bluebird'); let path = require('path'); -let child_process = Promise.promisifyAll(require('child_process')); +let child_process = require('child_process'); const PYTHON_BRIDGE_SCRIPT = path.join(__dirname, 'node_python_bridge.py'); @@ -57,6 +56,7 @@ function pythonBridge(opts) { } })); } + return wrapper; } @@ -142,11 +142,11 @@ function singleQueue() { last = new Promise(resolve => { done = resolve; }); - return new Promise((resolve, reject) => { - wait.finally(() => { - Promise.try(f).then(resolve, reject); + return promiseFinally(new Promise((resolve, reject) => { + promiseFinally(wait, () => { + promiseTry(f).then(resolve, reject); }); - }).finally(() => done()); + }), () => done()); }; } @@ -209,6 +209,21 @@ function serializePython(value) { } } +function promiseTry(f) { + return new Promise((resolve, reject) => { + try { + resolve(f()); + } catch (e) { + reject(e) + } + }); +} + +function promiseFinally(promise, cb) { + promise.then(cb, cb); + return promise; +} + pythonBridge.pythonBridge = pythonBridge; pythonBridge.PythonException = PythonException; pythonBridge.PythonBridgeNotConnected = PythonBridgeNotConnected; diff --git a/package.json b/package.json index e4c2124..0252e84 100644 --- a/package.json +++ b/package.json @@ -2,14 +2,15 @@ "name": "python-bridge", "version": "1.1.0", "description": "Node.js to Python bridge ✨🐍🚀✨", - "main": "index.js", + "main": "index-compiled.js", "types": "index.d.ts", "scripts": { "lint": "npm run lint:ts", - "lint:ts": "tslint --project tsconfig.json --type-check", + "lint:ts": "tslint --project tsconfig.json", "test": "npm run lint && npm run test:js && npm run test:ts", - "test:js": "tap test.js", - "test:ts": "tsc --lib ES2015 test_typescript.ts && tap test_typescript.js" + "test:js": "tap test-compiled.js", + "test:ts": "tsc --lib ES2015 test_typescript.ts && tap test_typescript.js", + "compile": "babel index.js --out-file index-compiled.js && babel test.js --out-file test-compiled.js" }, "repository": { "type": "git", @@ -26,14 +27,22 @@ ], "author": "Ryan Munro ", "license": "MIT", - "dependencies": { - "bluebird": "^3.5.0" - }, "devDependencies": { + "@babel/cli": "^7.4.3", + "@babel/core": "^7.4.3", + "@babel/preset-env": "^7.4.3", "@types/node": "^8.0.14", + "es6-promisify": "^6.0.1", + "p-timeout": "^3.1.0", "tap": "^10.7.0", "temp": "^0.8.3", "tslint": "^5.5.0", "typescript": "^2.4.1" + }, + "babel": { + "presets": [ + "@babel/preset-env" + ], + "plugins": [] } } diff --git a/test-compiled.js b/test-compiled.js new file mode 100644 index 0000000..2cfb0c9 --- /dev/null +++ b/test-compiled.js @@ -0,0 +1,798 @@ +'use strict'; + +var _ = _interopRequireWildcard(require("./")); + +var _tap = require("tap"); + +var _path = _interopRequireDefault(require("path")); + +var _es6Promisify = require("es6-promisify"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj["default"] = obj; return newObj; } } + +function _templateObject47() { + var data = _taggedTemplateLiteral(["(lambda x: x)(", ")"]); + + _templateObject47 = function _templateObject47() { + return data; + }; + + return data; +} + +function _templateObject46() { + var data = _taggedTemplateLiteral(["(lambda x: x)(", ")"]); + + _templateObject46 = function _templateObject46() { + return data; + }; + + return data; +} + +function _templateObject45() { + var data = _taggedTemplateLiteral(["hello(", ", ", ", ", ")"]); + + _templateObject45 = function _templateObject45() { + return data; + }; + + return data; +} + +function _templateObject44() { + var data = _taggedTemplateLiteral(["hello(", ")"]); + + _templateObject44 = function _templateObject44() { + return data; + }; + + return data; +} + +function _templateObject43() { + var data = _taggedTemplateLiteral(["hello(", ", ", ")"]); + + _templateObject43 = function _templateObject43() { + return data; + }; + + return data; +} + +function _templateObject42() { + var data = _taggedTemplateLiteral(["hello(", ")"]); + + _templateObject42 = function _templateObject42() { + return data; + }; + + return data; +} + +function _templateObject41() { + var data = _taggedTemplateLiteral(["hello()"]); + + _templateObject41 = function _templateObject41() { + return data; + }; + + return data; +} + +function _templateObject40() { + var data = _taggedTemplateLiteral(["\n def hello(a, b):\n return a + b\n "]); + + _templateObject40 = function _templateObject40() { + return data; + }; + + return data; +} + +function _templateObject39() { + var data = _taggedTemplateLiteral(["1 / 0"]); + + _templateObject39 = function _templateObject39() { + return data; + }; + + return data; +} + +function _templateObject38() { + var data = _taggedTemplateLiteral(["1 / 0"]); + + _templateObject38 = function _templateObject38() { + return data; + }; + + return data; +} + +function _templateObject37() { + var data = _taggedTemplateLiteral(["1 / 0"]); + + _templateObject37 = function _templateObject37() { + return data; + }; + + return data; +} + +function _templateObject36() { + var data = _taggedTemplateLiteral(["hello + 321"]); + + _templateObject36 = function _templateObject36() { + return data; + }; + + return data; +} + +function _templateObject35() { + var data = _taggedTemplateLiteral(["hello = 123"]); + + _templateObject35 = function _templateObject35() { + return data; + }; + + return data; +} + +function _templateObject34() { + var data = _taggedTemplateLiteral(["hello + 808"]); + + _templateObject34 = function _templateObject34() { + return data; + }; + + return data; +} + +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } + +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } + +function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } + +function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } + +function _templateObject33() { + var data = _taggedTemplateLiteral(["del hello"]); + + _templateObject33 = function _templateObject33() { + return data; + }; + + return data; +} + +function _templateObject32() { + var data = _taggedTemplateLiteral(["world + 191"]); + + _templateObject32 = function _templateObject32() { + return data; + }; + + return data; +} + +function _templateObject31() { + var data = _taggedTemplateLiteral(["world = 808"]); + + _templateObject31 = function _templateObject31() { + return data; + }; + + return data; +} + +function _templateObject30() { + var data = _taggedTemplateLiteral(["hello + 321"]); + + _templateObject30 = function _templateObject30() { + return data; + }; + + return data; +} + +function _templateObject29() { + var data = _taggedTemplateLiteral(["hello = 123"]); + + _templateObject29 = function _templateObject29() { + return data; + }; + + return data; +} + +function _templateObject28() { + var data = _taggedTemplateLiteral(["1 / 0"]); + + _templateObject28 = function _templateObject28() { + return data; + }; + + return data; +} + +function _templateObject27() { + var data = _taggedTemplateLiteral(["", " / ", ""]); + + _templateObject27 = function _templateObject27() { + return data; + }; + + return data; +} + +function _templateObject26() { + var data = _taggedTemplateLiteral(["\n hello = 123\n print(hello + world)\n world = 321\n "]); + + _templateObject26 = function _templateObject26() { + return data; + }; + + return data; +} + +function _templateObject25() { + var data = _taggedTemplateLiteral(["\n hello = 123\n print(hello + world)\n world = 321\n "]); + + _templateObject25 = function _templateObject25() { + return data; + }; + + return data; +} + +function _templateObject24() { + var data = _taggedTemplateLiteral(["1 + 2"]); + + _templateObject24 = function _templateObject24() { + return data; + }; + + return data; +} + +function _templateObject23() { + var data = _taggedTemplateLiteral(["\n from time import sleep\n sleep(9000)\n "]); + + _templateObject23 = function _templateObject23() { + return data; + }; + + return data; +} + +function _templateObject22() { + var data = _taggedTemplateLiteral(["\n import sys\n for line in sys.stdin:\n sys.stdout.write(line)\n sys.stdout.flush()\n "]); + + _templateObject22 = function _templateObject22() { + return data; + }; + + return data; +} + +function _templateObject21() { + var data = _taggedTemplateLiteral(["atomic()"]); + + _templateObject21 = function _templateObject21() { + return data; + }; + + return data; +} + +function _templateObject20() { + var data = _taggedTemplateLiteral(["\n def atomic():\n hello = 123\n return hello + 321\n "]); + + _templateObject20 = function _templateObject20() { + return data; + }; + + return data; +} + +function _templateObject19() { + var data = _taggedTemplateLiteral(["hello + 321"]); + + _templateObject19 = function _templateObject19() { + return data; + }; + + return data; +} + +function _templateObject18() { + var data = _taggedTemplateLiteral(["hello = 123"]); + + _templateObject18 = function _templateObject18() { + return data; + }; + + return data; +} + +function _templateObject17() { + var data = _taggedTemplateLiteral(["hello + 321"]); + + _templateObject17 = function _templateObject17() { + return data; + }; + + return data; +} + +function _templateObject16() { + var data = _taggedTemplateLiteral(["del hello"]); + + _templateObject16 = function _templateObject16() { + return data; + }; + + return data; +} + +function _templateObject15() { + var data = _taggedTemplateLiteral(["hello + 321"]); + + _templateObject15 = function _templateObject15() { + return data; + }; + + return data; +} + +function _templateObject14() { + var data = _taggedTemplateLiteral(["hello = 123"]); + + _templateObject14 = function _templateObject14() { + return data; + }; + + return data; +} + +function _templateObject13() { + var data = _taggedTemplateLiteral(["hello(", ", ", ")"]); + + _templateObject13 = function _templateObject13() { + return data; + }; + + return data; +} + +function _templateObject12() { + var data = _taggedTemplateLiteral(["\n def hello(a, b):\n return a + b\n "]); + + _templateObject12 = function _templateObject12() { + return data; + }; + + return data; +} + +function _templateObject11() { + var data = _taggedTemplateLiteral(["dict(baz=123, **", ")"]); + + _templateObject11 = function _templateObject11() { + return data; + }; + + return data; +} + +function _templateObject10() { + var data = _taggedTemplateLiteral(["sorted(", ")"]); + + _templateObject10 = function _templateObject10() { + return data; + }; + + return data; +} + +function _templateObject9() { + var data = _taggedTemplateLiteral(["sorted(", ")"]); + + _templateObject9 = function _templateObject9() { + return data; + }; + + return data; +} + +function _templateObject8() { + var data = _taggedTemplateLiteral(["math.sqrt(9)"]); + + _templateObject8 = function _templateObject8() { + return data; + }; + + return data; +} + +function _templateObject7() { + var data = _taggedTemplateLiteral(["import math"]); + + _templateObject7 = function _templateObject7() { + return data; + }; + + return data; +} + +function _templateObject6() { + var data = _taggedTemplateLiteral(["type('').__name__"]); + + _templateObject6 = function _templateObject6() { + return data; + }; + + return data; +} + +function _templateObject5() { + var data = _taggedTemplateLiteral(["type('').__name__"]); + + _templateObject5 = function _templateObject5() { + return data; + }; + + return data; +} + +function _templateObject4() { + var data = _taggedTemplateLiteral(["from __future__ import unicode_literals"]); + + _templateObject4 = function _templateObject4() { + return data; + }; + + return data; +} + +function _templateObject3() { + var data = _taggedTemplateLiteral(["type('').__name__"]); + + _templateObject3 = function _templateObject3() { + return data; + }; + + return data; +} + +function _templateObject2() { + var data = _taggedTemplateLiteral(["sys.version_info[0] > 2"]); + + _templateObject2 = function _templateObject2() { + return data; + }; + + return data; +} + +function _templateObject() { + var data = _taggedTemplateLiteral(["import sys"]); + + _templateObject = function _templateObject() { + return data; + }; + + return data; +} + +function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } + +var mkdirTemp = (0, _es6Promisify.promisify)(require('temp').mkdir); +(0, _tap.test)('leave __future__ alone!', function (t) { + t.plan(2); + var python = (0, _["default"])(); + python.ex(_templateObject()); + python(_templateObject2()).then(function (py3) { + python(_templateObject3()).then(function (x) { + return t.equal(x, 'str'); + }); + python.ex(_templateObject4()); + + if (py3) { + python(_templateObject5()).then(function (x) { + return t.equal(x, 'str'); + }); + } else { + python(_templateObject6()).then(function (x) { + return t.equal(x, 'unicode'); + }); + } + }).then(function () { + python.end(); + }, function () { + python.end(); + }); +}); +(0, _tap.test)('readme', function (t) { + t.test('example', function (t) { + t.plan(2); + var python = (0, _["default"])(); + python.ex(_templateObject7()); + python(_templateObject8()).then(function (x) { + return t.equal(x, 3); + }); + var list = [3, 4, 2, 1]; + python(_templateObject9(), list).then(function (x) { + return t.deepEqual(x, list.sort()); + }); + python.end(); + }); + t.test('expression', function (t) { + t.plan(2); + var python = (0, _["default"])(); // Interpolates arguments using JSON serialization. + + python(_templateObject10(), [6, 4, 1, 3]).then(function (x) { + return t.deepEqual(x, [1, 3, 4, 6]); + }); // Passing key-value arguments + + var obj = { + hello: 'world', + foo: 'bar' + }; + python(_templateObject11(), obj).then(function (x) { + t.deepEqual(x, { + baz: 123, + hello: 'world', + foo: 'bar' + }); + }); + python.end(); + }); + t.test('execute', function (t) { + t.plan(1); + var python = (0, _["default"])(); + var a = 123, + b = 321; + python.ex(_templateObject12()); + python(_templateObject13(), a, b).then(function (x) { + return t.equal(x, a + b); + }); + python.end(); + }); + t.test('lock', function (t) { + t.plan(3); + var python = (0, _["default"])(); + python.lock(function (python) { + python.ex(_templateObject14()); + var value = python(_templateObject15()); + return new Promise(function (resolve) { + return setTimeout(function () { + python.ex(_templateObject16()).then(function () { + return resolve(value); + }); + }, 100); + }); + }).then(function (x) { + return t.equal(x, 444); + }); + python(_templateObject17())["catch"](function (e) { + if ((0, _.isPythonException)('NameError', e)) { + t.ok(true); + } + }); + python.ex(_templateObject18()); + python(_templateObject19()).then(function (x) { + return t.equal(x, 444); + }); + python.disconnect(); + }); + t.test('lock recommended', function (t) { + t.plan(1); + var python = (0, _["default"])(); + python.ex(_templateObject20()); + python(_templateObject21()).then(function (x) { + return t.equal(x, 444); + }); + python.disconnect(); + }); + t.test('stdout', function (t) { + t.plan(1); + var python = (0, _["default"])({ + stdio: ['pipe', 'pipe', process.stderr] + }); + mkdirTemp('node-python-bridge-test').then(function (tempdir) { + var OUTPUT = _path["default"].join(tempdir, 'output.txt'); + + var fs = require('fs'); + + var readFileAsync = (0, _es6Promisify.promisify)(fs.readFile); + var fileWriter = fs.createWriteStream(OUTPUT); + python.stdout.pipe(fileWriter); // listen on Python process's stdout + + python.ex(_templateObject22()).then(function () { + fileWriter.end(); + readFileAsync(OUTPUT, { + encoding: 'utf8' + }).then(function (x) { + t.equal(x.replace(/\r/g, ''), 'hello\nworld\n'); + }); + }); // write to Python process's stdin + + python.stdin.write('hello\n'); + setTimeout(function () { + python.stdin.write('world\n'); + python.stdin.end(); + }, 10); + python.end(); + }); + }); + t.test('kill', function (t) { + t.plan(2); + + var pTimeout = require('p-timeout'); + + var python = (0, _["default"])(); + pTimeout(python.ex(_templateObject23()), 100).then(function (x) { + t.ok(false); + })["catch"](function (e) { + if (e instanceof pTimeout.TimeoutError) { + python.kill('SIGKILL'); + t.ok(true); + python = (0, _["default"])(); + } + }); + setTimeout(function () { + python(_templateObject24()).then(function (x) { + return t.equal(x, 3); + }); + python.disconnect(); + }, 200); + }); + t.test('exceptions', function (t) { + t.plan(6); + var python = (0, _["default"])(); + python.ex(_templateObject25())["catch"](function (e) { + if (e instanceof python.Exception) { + t.ok(true); + } + }); + python.ex(_templateObject26())["catch"](function (e) { + if (e instanceof _["default"].PythonException) { + t.ok(true); + } + }); + + function pyDivide(numerator, denominator) { + return python(_templateObject27(), numerator, denominator)["catch"](function (e) { + if (python.isException('ZeroDivisionError', e)) { + return Promise.resolve(Infinity); + } + }); + } + + pyDivide(1, 0).then(function (x) { + t.equal(x, Infinity); + t.equal(1 / 0, Infinity); + }); + pyDivide(6, 2).then(function (x) { + return t.equal(x, 3); + }); + python(_templateObject28())["catch"](function (e) { + if (_["default"].isPythonException('ZeroDivisionError', e)) { + return Promise.resolve(Infinity); + } + }).then(function (x) { + return t.equal(x, 1 / 0); + }); + python.disconnect(); + }); + t.end(); +}); +(0, _tap.test)('nested locks', function (t) { + t.plan(3); + var python = (0, _["default"])(); + python.lock(function (python) { + python.ex(_templateObject29()); + var $value1 = python(_templateObject30()); + var $value2 = python.lock(function (python) { + python.ex(_templateObject31()); + return python(_templateObject32()); + }); + return new Promise(function (resolve) { + return setTimeout(function () { + python.ex(_templateObject33()).then(function () { + return Promise.all([$value1, $value2]).then(function (_ref) { + var _ref2 = _slicedToArray(_ref, 2), + value1 = _ref2[0], + value2 = _ref2[1]; + + resolve(value1 + value2); + }); + }); + }, 100); + }); + }).then(function (x) { + return t.equal(x, 1443); + }); + python(_templateObject34())["catch"](function (e) { + if ((0, _.isPythonException)('NameError', e)) { + t.ok(true); + } + }); + python.ex(_templateObject35()); + python(_templateObject36()).then(function (x) { + return t.equal(x, 444); + }); + python.disconnect(); +}); +(0, _tap.test)('exceptions', function (t) { + t.plan(3); + var python = (0, _["default"])(); + python(_templateObject37())["catch"](function () { + return t.ok(true); + }); + python(_templateObject38())["catch"](function (e) { + if (e instanceof ReferenceError) { + t.ok(false); + } else { + return Promise.reject(e); + } + })["catch"](function (e) { + if (e instanceof _.PythonException) { + t.ok(true); + } + }); + python(_templateObject39())["catch"](function (e) { + if ((0, _.isPythonException)('IOError', e)) { + t.ok(false); + } else { + return Promise.reject(e); + } + })["catch"](function (e) { + if ((0, _.isPythonException)('ZeroDivisionError', e)) { + t.ok(true); + } + }); + python.end(); +}); +(0, _tap.test)('json interpolation', function (t) { + t.equal(_["default"].json(_templateObject40()), 'def hello(a, b):\n return a + b\n'); + t.equal(_["default"].json(_templateObject41()), 'hello()'); + t.equal(_["default"].json(_templateObject42(), 'world'), 'hello("world")'); + t.equal(_["default"].json(_templateObject43(), 'world', [1, 2, 3]), 'hello("world", [1, 2, 3])'); + t.equal(_["default"].json(_templateObject44(), new Map([[1, 2], [3, 4]])), 'hello({1: 2, 3: 4})'); + t.equal(_["default"].json(_templateObject45(), NaN, Infinity, -Infinity), "hello(float('nan'), float('inf'), float('-inf'))"); + t.end(); +}); +(0, _tap.test)('bug #22 returning NaN or infinity does not work', function (t) { + t.plan(1); + var s = { + a: NaN, + b: Infinity, + c: -Infinity + }; + var python = (0, _["default"])(); + python(_templateObject46(), s).then(function (x) { + return t.deepEqual(x, s); + }); + python.end(); +}); +(0, _tap.test)('bug #24 support more than just numbers and strings', function (t) { + t.plan(1); + var s = { + a: 'asdf', + b: 1, + c: true, + d: [1, 2, null] + }; + var python = (0, _["default"])(); + python(_templateObject47(), s).then(function (x) { + return t.deepEqual(x, s); + }); + python.end(); +}); diff --git a/test.js b/test.js index 471c0f1..13cb315 100644 --- a/test.js +++ b/test.js @@ -1,17 +1,16 @@ 'use strict'; -let pythonBridge = require('./'); -let PythonException = pythonBridge.PythonException; -let isPythonException = pythonBridge.isPythonException; -let test = require('tap').test; -let Promise = require('bluebird'); -let mkdirTemp = Promise.promisify(require('temp').mkdir); -let path = require('path'); +import pythonBridge from './'; +import {PythonException, isPythonException} from './'; +import {test} from 'tap'; +import path from 'path'; +import {promisify} from 'es6-promisify'; +const mkdirTemp = promisify(require('temp').mkdir); test('leave __future__ alone!', t => { t.plan(2); - let python = pythonBridge(); + const python = pythonBridge(); python.ex`import sys`; python`sys.version_info[0] > 2`.then(py3 => { python`type('').__name__`.then(x => t.equal(x, 'str')); @@ -21,7 +20,9 @@ test('leave __future__ alone!', t => { } else { python`type('').__name__`.then(x => t.equal(x, 'unicode')); } - }).finally(() => { + }).then(() => { + python.end(); + }, () => { python.end(); }); }); @@ -30,11 +31,11 @@ test('readme', t => { t.test('example', t => { t.plan(2); - let python = pythonBridge(); + const python = pythonBridge(); python.ex`import math`; python`math.sqrt(9)`.then(x => t.equal(x, 3)); - let list = [3, 4, 2, 1]; + const list = [3, 4, 2, 1]; python`sorted(${list})`.then(x => t.deepEqual(x, list.sort())); python.end(); @@ -43,12 +44,12 @@ test('readme', t => { t.test('expression', t => { t.plan(2); - let python = pythonBridge(); + const python = pythonBridge(); // Interpolates arguments using JSON serialization. python`sorted(${[6, 4, 1, 3]})`.then(x => t.deepEqual(x, [1, 3, 4, 6])); // Passing key-value arguments - let obj = {hello: 'world', foo: 'bar'}; + const obj = {hello: 'world', foo: 'bar'}; python`dict(baz=123, **${obj})`.then(x => { t.deepEqual(x, {baz: 123, hello: 'world', foo: 'bar'}); }); @@ -58,8 +59,8 @@ test('readme', t => { t.test('execute', t => { t.plan(1); - let python = pythonBridge(); - let a = 123, b = 321; + const python = pythonBridge(); + const a = 123, b = 321; python.ex` def hello(a, b): return a + b @@ -71,28 +72,31 @@ test('readme', t => { t.test('lock', t => { t.plan(3); - let python = pythonBridge(); + const python = pythonBridge(); python.lock(python => { python.ex`hello = 123`; - let value = python`hello + 321`; + const value = python`hello + 321`; return new Promise(resolve => setTimeout(() => { python.ex`del hello`.then(() => resolve(value)); }, 100)); }).then(x => t.equal(x, 444)); - python`hello + 321`.catch(isPythonException('NameError'), () => t.ok(true)); + python`hello + 321`.catch(e => { + if (isPythonException('NameError', e)) { + t.ok(true); + } + }); python.ex`hello = 123`; python`hello + 321`.then(x => t.equal(x, 444)); python.disconnect(); }); - t.test('lock recommended', t => { t.plan(1); - let python = pythonBridge(); + const python = pythonBridge(); python.ex` def atomic(): @@ -106,15 +110,14 @@ test('readme', t => { t.test('stdout', t => { t.plan(1); - let python = pythonBridge({stdio: ['pipe', 'pipe', process.stderr]}); + const python = pythonBridge({stdio: ['pipe', 'pipe', process.stderr]}); mkdirTemp('node-python-bridge-test').then(tempdir => { const OUTPUT = path.join(tempdir, 'output.txt'); - let Promise = require('bluebird'); - let fs = Promise.promisifyAll(require('fs')); - - let fileWriter = fs.createWriteStream(OUTPUT); + const fs = require('fs'); + const readFileAsync = promisify(fs.readFile); + const fileWriter = fs.createWriteStream(OUTPUT); python.stdout.pipe(fileWriter); @@ -126,7 +129,7 @@ test('readme', t => { sys.stdout.flush() `.then(function () { fileWriter.end(); - fs.readFileAsync(OUTPUT, {encoding: 'utf8'}).then(x => { + readFileAsync(OUTPUT, {encoding: 'utf8'}).then(x => { t.equal(x.replace(/\r/g, ''), 'hello\nworld\n') }); }); @@ -145,49 +148,61 @@ test('readme', t => { t.test('kill', t => { t.plan(2); + const pTimeout = require('p-timeout'); let python = pythonBridge(); - let Promise = require('bluebird'); - - python.ex` + pTimeout(python.ex` from time import sleep sleep(9000) - `.timeout(100).then(x => { + `, 100).then(x => { t.ok(false); - }).catch(Promise.TimeoutError, exit_code => { - python.kill('SIGKILL'); - t.ok(true); - python = pythonBridge(); + }).catch(e => { + if (e instanceof pTimeout.TimeoutError) { + python.kill('SIGKILL'); + t.ok(true); + python = pythonBridge(); + } }); setTimeout(() => { python`1 + 2`.then(x => t.equal(x, 3)); python.disconnect(); }, 200); - - // python.disconnect(); }); t.test('exceptions', t => { t.plan(6); - let python = pythonBridge(); + const python = pythonBridge(); python.ex` hello = 123 print(hello + world) world = 321 - `.catch(python.Exception, () => t.ok(true)); + `.catch(e => { + if (e instanceof python.Exception) { + t.ok(true); + } + }); python.ex` hello = 123 print(hello + world) world = 321 - `.catch(pythonBridge.PythonException, () => t.ok(true)); + `.catch(e => { + if (e instanceof pythonBridge.PythonException) { + t.ok(true); + } + }); function pyDivide(numerator, denominator) { return python`${numerator} / ${denominator}` - .catch(python.isException('ZeroDivisionError'), () => Promise.resolve(Infinity)); + .catch(e => { + if (python.isException('ZeroDivisionError', e)) { + return Promise.resolve(Infinity); + } + }); } + pyDivide(1, 0).then(x => { t.equal(x, Infinity); t.equal(1 / 0, Infinity); @@ -195,7 +210,11 @@ test('readme', t => { pyDivide(6, 2).then(x => t.equal(x, 3)); python`1 / 0` - .catch(pythonBridge.isPythonException('ZeroDivisionError'), () => Promise.resolve(Infinity)) + .catch(e => { + if (pythonBridge.isPythonException('ZeroDivisionError', e)) { + return Promise.resolve(Infinity); + } + }) .then(x => t.equal(x, 1 / 0)); python.disconnect(); @@ -207,25 +226,29 @@ test('readme', t => { test('nested locks', t => { t.plan(3); - let python = pythonBridge(); + const python = pythonBridge(); python.lock(python => { python.ex`hello = 123`; - let $value1 = python`hello + 321`; - let $value2 = python.lock(python => { + const $value1 = python`hello + 321`; + const $value2 = python.lock(python => { python.ex`world = 808`; return python`world + 191`; }); return new Promise(resolve => setTimeout(() => { python.ex`del hello`.then(() => { - return Promise.all([$value1, $value2]).spread((value1, value2) => { + return Promise.all([$value1, $value2]).then(([value1, value2]) => { resolve(value1 + value2); }) }); }, 100)); }).then(x => t.equal(x, 1443)); - python`hello + 808`.catch(isPythonException('NameError'), () => t.ok(true)); + python`hello + 808`.catch(e => { + if (isPythonException('NameError', e)) { + t.ok(true); + } + }); python.ex`hello = 123`; python`hello + 321`.then(x => t.equal(x, 444)); @@ -235,14 +258,34 @@ test('nested locks', t => { test('exceptions', t => { t.plan(3); - let python = pythonBridge(); + const python = pythonBridge(); python`1 / 0`.catch(() => t.ok(true)); python`1 / 0` - .catch(ReferenceError, () => t.ok(false)) - .catch(PythonException, () => t.ok(true)); + .catch(e => { + if (e instanceof ReferenceError) { + t.ok(false); + } else { + return Promise.reject(e); + } + }) + .catch(e => { + if (e instanceof PythonException) { + t.ok(true); + } + }); python`1 / 0` - .catch(isPythonException('IOError'), () => t.ok(false)) - .catch(isPythonException('ZeroDivisionError'), () => t.ok(true)); + .catch(e => { + if (isPythonException('IOError', e)) { + t.ok(false) + } else { + return Promise.reject(e); + } + }) + .catch(e => { + if (isPythonException('ZeroDivisionError', e)) { + t.ok(true) + } + }); python.end(); }); diff --git a/test_typescript.ts b/test_typescript.ts index 577250b..26514a6 100644 --- a/test_typescript.ts +++ b/test_typescript.ts @@ -1,7 +1,8 @@ -import { test } from 'tap'; -import { join as path_join } from 'path'; -import { promisify } from 'bluebird'; -import { pythonBridge, PythonException, isPythonException } from './index'; +import {test} from 'tap'; +import {join as path_join} from 'path'; +import {promisify} from 'es6-promisify'; +import {isPythonException, pythonBridge, PythonException} from './index'; +import pTimeout from 'p-timeout'; const mkdirTemp = promisify(require('temp').mkdir); @@ -22,7 +23,7 @@ test('readme', t => { }); t.test('expression', async assert => { - let python = pythonBridge(); + const python = pythonBridge(); try { // Interpolates arguments using JSON serialization. assert.deepEqual([1, 3, 4, 6], await python`sorted(${[6, 4, 1, 3]})`); @@ -55,7 +56,7 @@ test('readme', t => { t.test('lock', async assert => { const python = pythonBridge(); try { - const x: number = await python.lock(async python =>{ + const x: number = await python.lock(async python => { await python.ex`hello = 123`; return await python`hello + 321`; }); @@ -70,7 +71,7 @@ test('readme', t => { t.test('lock recommended', async assert => { const python = pythonBridge(); try { - const x: number = await python.lock(async python =>{ + const x: number = await python.lock(async python => { await python.ex`hello = 123`; return await python`hello + 321`; }); @@ -81,16 +82,15 @@ test('readme', t => { } }); - t.test('stdout', async assert => { - const python = pythonBridge({stdio: ['pipe', 'pipe', process.stderr]}) + const python = pythonBridge({stdio: ['pipe', 'pipe', process.stderr]}); try { const tempdir = await mkdirTemp('node-python-bridge-test'); const OUTPUT = path_join(tempdir, 'output.txt'); - const { delay, promisifyAll } = require('bluebird'); - const { createWriteStream, readFileAsync } = promisifyAll(require('fs')); + const {createWriteStream, readFile} = require('fs'); + const readFileAsync = promisify(readFile); const fileWriter = createWriteStream(OUTPUT); python.stdout.pipe(fileWriter); @@ -105,7 +105,7 @@ test('readme', t => { // write to Python process's stdin python.stdin.write('hello\n'); - await delay(10); + await new Promise(resolve => setTimeout(resolve, 10)); python.stdin.write('world\n'); // close python's stdin, and wait for python to finish writing @@ -121,19 +121,16 @@ test('readme', t => { }); t.test('kill', async assert => { - let python = pythonBridge(); - let {TimeoutError} = require('bluebird'); - try { - await python.ex` + await pTimeout(python.ex` from time import sleep sleep(9000) - `.timeout(100); + `, 100); assert.ok(false); // should not reach this } catch (e) { - if (e instanceof TimeoutError) { + if (e instanceof pTimeout.TimeoutError) { python.kill('SIGKILL'); python = pythonBridge(); } else { @@ -144,7 +141,7 @@ test('readme', t => { }); t.test('exceptions', async assert => { - let python = pythonBridge(); + const python = pythonBridge(); try { await python.ex` @@ -172,10 +169,11 @@ test('readme', t => { assert.equal(Infinity, await pyDivide(1, 0)); assert.equal(1 / 0, await pyDivide(1, 0)); } + await main(); python.end(); }); t.end(); -}); \ No newline at end of file +}); diff --git a/tsconfig.json b/tsconfig.json index 2c3a895..f14dfee 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,6 +17,9 @@ , "noLib": false , "traceResolution": false } + , "linterOptions": { + "typeCheck": true + } , "exclude": [ "node_modules/" , "dist/" diff --git a/tslint.json b/tslint.json index fd4952b..c2ae87a 100644 --- a/tslint.json +++ b/tslint.json @@ -54,11 +54,11 @@ "no-eval": true, "no-internal-module": true, "no-require-imports": false, - "no-shadowed-variable": true, + "no-shadowed-variable": false, "no-string-literal": false, "no-switch-case-fall-through": true, "no-trailing-whitespace": true, - "no-unused-expression": true, + "no-unused-expression": false, "no-use-before-declare": true, "no-var-keyword": true, "no-var-requires": false,