diff --git a/index.d.ts b/index.d.ts index 126e1f6..54851f2 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,21 +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; diff --git a/index.js b/index.js index c19811d..faad963 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'); @@ -142,11 +141,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 +208,22 @@ function serializePython(value) { } } +function promiseTry(f) { + // return Promise.try(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..0ce83ff 100644 --- a/package.json +++ b/package.json @@ -26,11 +26,9 @@ ], "author": "Ryan Munro ", "license": "MIT", - "dependencies": { - "bluebird": "^3.5.0" - }, "devDependencies": { "@types/node": "^8.0.14", + "es6-promisify": "^6.0.1", "tap": "^10.7.0", "temp": "^0.8.3", "tslint": "^5.5.0", diff --git a/test.js b/test.js index 471c0f1..d06c249 100644 --- a/test.js +++ b/test.js @@ -4,9 +4,9 @@ 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'); +const promisify = require('es6-promisify').promisify; +const mkdirTemp = promisify(require('temp').mkdir); test('leave __future__ alone!', t => { t.plan(2); @@ -21,7 +21,9 @@ test('leave __future__ alone!', t => { } else { python`type('').__name__`.then(x => t.equal(x, 'unicode')); } - }).finally(() => { + }).then(() => { + python.end(); + }, () => { python.end(); }); }); @@ -81,14 +83,17 @@ test('readme', t => { }, 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); @@ -111,9 +116,8 @@ test('readme', t => { mkdirTemp('node-python-bridge-test').then(tempdir => { const OUTPUT = path.join(tempdir, 'output.txt'); - let Promise = require('bluebird'); - let fs = Promise.promisifyAll(require('fs')); - + const fs = require('fs'); + const readFileAsync = promisify(fs.readFile); let fileWriter = fs.createWriteStream(OUTPUT); python.stdout.pipe(fileWriter); @@ -126,7 +130,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') }); }); @@ -147,24 +151,22 @@ test('readme', t => { let python = pythonBridge(); - let Promise = require('bluebird'); - - python.ex` + promiseTimeout(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 PromiseTimeout) { + 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 => { @@ -176,17 +178,29 @@ test('readme', t => { 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); @@ -195,7 +209,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(); @@ -218,14 +236,18 @@ test('nested locks', t => { }); return new Promise(resolve => setTimeout(() => { python.ex`del hello`.then(() => { - return Promise.all([$value1, $value2]).spread((value1, value2) => { - resolve(value1 + value2); + return Promise.all([$value1, $value2]).then((args) => { + resolve(args[0] + args[1]); }) }); }, 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)); @@ -238,11 +260,11 @@ test('exceptions', t => { let 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(); }); @@ -274,3 +296,31 @@ test('bug #24 support more than just numbers and strings', t => { python`(lambda x: x)(${s})`.then(x => t.deepEqual(x, s)); python.end(); }); + +function promiseTimeout(promise, delay) { + return new Promise((resolve, reject) => { + let timer = setTimeout(() => { + timer = null; + reject(new PromiseTimeout()); + }, delay); + + promise.then(function () { + if (timer === null) { + return; + } + clearTimeout(timer); + timer = null; + resolve.apply(this, arguments); + }, function () { + if (timer === null) { + return; + } + clearTimeout(timer); + timer = null; + reject.apply(this, arguments); + }) + }) +} + +class PromiseTimeout extends Error { +}