mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Nicer wrapper for duktape
This commit is contained in:
parent
655c9499fd
commit
6186a266e7
@ -170,7 +170,7 @@ def test_icu():
|
||||
|
||||
def test_dukpy():
|
||||
print ('Testing dukpy')
|
||||
from duktape.tests import test_build
|
||||
from duktape import test_build
|
||||
test_build()
|
||||
print ('dukpy OK!')
|
||||
|
||||
|
@ -7,9 +7,9 @@ __copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
__all__ = ['dukpy', 'Context', 'undefined']
|
||||
__all__ = ['dukpy', 'Context', 'undefined', 'JSError']
|
||||
|
||||
import errno, os
|
||||
import errno, os, sys
|
||||
from functools import partial
|
||||
|
||||
from calibre.constants import plugins
|
||||
@ -28,15 +28,60 @@ def load_file(base_dirs, name):
|
||||
raise
|
||||
raise EnvironmentError('No module named: %s found in the base directories: %s' % (name, os.pathsep.join(base_dirs)))
|
||||
|
||||
def Context(base_dirs=()):
|
||||
ans = Context_()
|
||||
if not base_dirs:
|
||||
base_dirs = (os.getcwdu(),)
|
||||
ans.g.Duktape.load_file = partial(load_file, base_dirs or (os.getcwdu(),))
|
||||
ans.eval('''
|
||||
console = { log: function() { print(Array.prototype.join.call(arguments, ' ')); } };
|
||||
Duktape.modSearch = function (id, require, exports, module) {
|
||||
return Duktape.load_file(id);
|
||||
}
|
||||
''')
|
||||
return ans
|
||||
class JSError(Exception):
|
||||
|
||||
def __init__(self, e):
|
||||
e = e.args[0]
|
||||
Exception.__init__(self, e.toString())
|
||||
self.name = e.name
|
||||
self.js_message = e.message
|
||||
self.fileName = e.fileName
|
||||
self.lineNumber = e.lineNumber
|
||||
self.stack = e.stack
|
||||
|
||||
class Context(object):
|
||||
|
||||
def __init__(self, base_dirs=()):
|
||||
self._ctx = Context_()
|
||||
self.g = self._ctx.g
|
||||
self.g.Duktape.load_file = partial(load_file, base_dirs or (os.getcwdu(),))
|
||||
self.eval('''
|
||||
console = { log: function() { print(Array.prototype.join.call(arguments, ' ')); } };
|
||||
Duktape.modSearch = function (id, require, exports, module) {
|
||||
return Duktape.load_file(id);
|
||||
}
|
||||
''')
|
||||
|
||||
def eval(self, code='', noreturn=False):
|
||||
try:
|
||||
self._ctx.eval(code, noreturn)
|
||||
except dukpy.JSError as e:
|
||||
raise JSError(e)
|
||||
|
||||
def eval_file(self, path, noreturn=False):
|
||||
try:
|
||||
self._ctx.eval_file(path, noreturn)
|
||||
except dukpy.JSError as e:
|
||||
raise JSError(e)
|
||||
|
||||
def test_build():
|
||||
import unittest
|
||||
|
||||
def load_tests(loader, suite, pattern):
|
||||
from duktape import tests
|
||||
for x in vars(tests).itervalues():
|
||||
if isinstance(x, type) and issubclass(x, unittest.TestCase):
|
||||
tests = loader.loadTestsFromTestCase(x)
|
||||
suite.addTests(tests)
|
||||
return suite
|
||||
|
||||
class TestRunner(unittest.main):
|
||||
|
||||
def createTests(self):
|
||||
tl = unittest.TestLoader()
|
||||
suite = unittest.TestSuite()
|
||||
self.test = load_tests(tl, suite, None)
|
||||
|
||||
result = TestRunner(verbosity=0, buffer=True, catchbreak=True, failfast=True, argv=sys.argv[:1], exit=False).result
|
||||
if not result.wasSuccessful():
|
||||
raise SystemExit(1)
|
||||
|
@ -98,8 +98,12 @@ static PyObject *DukContext_eval(DukContext *self, PyObject *args, PyObject *kw)
|
||||
if (temp && PyObject_IsTrue(temp)) noresult = 1;
|
||||
|
||||
if (duk_peval_string(self->ctx, code) != 0) {
|
||||
PyErr_Format(PyExc_SyntaxError, "%s",
|
||||
duk_safe_to_string(self->ctx, -1));
|
||||
temp = duk_to_python(self->ctx, -1);
|
||||
if (temp) {
|
||||
PyErr_SetObject(JSError, temp);
|
||||
Py_DECREF(temp);
|
||||
}
|
||||
duk_pop(self->ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -128,8 +132,12 @@ static PyObject *DukContext_eval_file(DukContext *self, PyObject *args, PyObject
|
||||
if (temp && PyObject_IsTrue(temp)) noresult = 1;
|
||||
|
||||
if (duk_peval_file(self->ctx, path) != 0) {
|
||||
PyErr_Format(PyExc_SyntaxError,
|
||||
"%s:%s", path, duk_safe_to_string(self->ctx, -1));
|
||||
temp = duk_to_python(self->ctx, -1);
|
||||
if (temp) {
|
||||
PyErr_SetObject(JSError, temp);
|
||||
Py_DECREF(temp);
|
||||
}
|
||||
duk_pop(self->ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ typedef struct DukEnum_ DukEnum;
|
||||
|
||||
PyObject DukUndefined;
|
||||
#define Duk_undefined (&DukUndefined)
|
||||
extern PyObject *JSError;
|
||||
|
||||
|
||||
/* context.c */
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "dukpy.h"
|
||||
|
||||
PyObject *JSError = NULL;
|
||||
|
||||
/* ARGSUSED */
|
||||
static PyObject *
|
||||
undefined_repr(PyObject *op)
|
||||
@ -131,6 +133,9 @@ initdukpy(void)
|
||||
|
||||
Py_INCREF(Duk_undefined);
|
||||
PyModule_AddObject(mod, "undefined", (PyObject *)Duk_undefined);
|
||||
|
||||
JSError = PyErr_NewException("dukpy.JSError", NULL, NULL);
|
||||
if (JSError) PyModule_AddObject(mod, "JSError", JSError);
|
||||
}
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
|
@ -1,7 +1,8 @@
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
from duktape import Context, undefined
|
||||
from duktape import dukpy
|
||||
undefined, JSError, Context = dukpy.undefined, dukpy.JSError, dukpy.Context
|
||||
|
||||
class ContextTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
@ -129,6 +130,24 @@ class EvalTests(unittest.TestCase):
|
||||
def test_eval_kwargs(self):
|
||||
self.assertEqual(self.ctx.eval(code="1+1"), 2)
|
||||
|
||||
def test_eval_errors(self):
|
||||
try:
|
||||
self.ctx.eval('1+/1')
|
||||
self.assert_('No error raised for malformed js')
|
||||
except JSError as e:
|
||||
e = e.args[0]
|
||||
self.assertEqual('SyntaxError', e.name)
|
||||
self.assertEqual(1, e.lineNumber)
|
||||
self.assertIn('line 1', e.toString())
|
||||
|
||||
try:
|
||||
self.ctx.eval('\na()')
|
||||
self.assert_('No error raised for malformed js')
|
||||
except JSError as e:
|
||||
e = e.args[0]
|
||||
self.assertEqual('ReferenceError', e.name)
|
||||
self.assertEqual(2, e.lineNumber)
|
||||
|
||||
def test_eval_noreturn(self):
|
||||
self.assertIsNone(self.ctx.eval("1+1", noreturn=True))
|
||||
|
||||
@ -148,27 +167,4 @@ class EvalTests(unittest.TestCase):
|
||||
def test_eval_file_noreturn(self):
|
||||
self.assertIsNone(self.ctx.eval_file(self.testfile, noreturn=True))
|
||||
|
||||
def load_tests(loader, suite, pattern):
|
||||
for x in globals().itervalues():
|
||||
if isinstance(x, type) and issubclass(x, unittest.TestCase):
|
||||
tests = loader.loadTestsFromTestCase(x)
|
||||
suite.addTests(tests)
|
||||
return suite
|
||||
|
||||
class TestRunner(unittest.main):
|
||||
|
||||
def createTests(self):
|
||||
tl = unittest.TestLoader()
|
||||
suite = unittest.TestSuite()
|
||||
self.test = load_tests(tl, suite, None)
|
||||
|
||||
def run(verbosity=4):
|
||||
TestRunner(verbosity=verbosity, exit=False)
|
||||
|
||||
def test_build():
|
||||
result = TestRunner(verbosity=0, buffer=True, catchbreak=True, failfast=True, argv=sys.argv[:1], exit=False).result
|
||||
if not result.wasSuccessful():
|
||||
raise SystemExit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
|
Loading…
x
Reference in New Issue
Block a user