mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 18:24:30 -04:00
Improve error handling in the RS REPL
This commit is contained in:
parent
cea314f0d9
commit
8aaa1d0cdd
@ -10,7 +10,7 @@ import os, json, sys, re, atexit, errno
|
|||||||
from threading import local
|
from threading import local
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from Queue import Queue
|
from Queue import Queue, Empty
|
||||||
|
|
||||||
from duktape import Context, JSError, to_python
|
from duktape import Context, JSError, to_python
|
||||||
from calibre.constants import cache_dir
|
from calibre.constants import cache_dir
|
||||||
@ -223,6 +223,14 @@ class Repl(Thread):
|
|||||||
'lib_path': self.libdir or os.path.dirname(P(COMPILER_PATH)) # TODO: Change this to load pyj files from the src code
|
'lib_path': self.libdir or os.path.dirname(P(COMPILER_PATH)) # TODO: Change this to load pyj files from the src code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def get_from_repl(self):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
return self.from_repl.get(True, 1)
|
||||||
|
except Empty:
|
||||||
|
if not self.is_alive():
|
||||||
|
raise SystemExit(1)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.init_ctx()
|
self.init_ctx()
|
||||||
rl = None
|
rl = None
|
||||||
@ -252,6 +260,8 @@ class Repl(Thread):
|
|||||||
''')
|
''')
|
||||||
rl = self.ctx.g.rl
|
rl = self.ctx.g.rl
|
||||||
self.ctx.eval('module.exports(repl_options)')
|
self.ctx.eval('module.exports(repl_options)')
|
||||||
|
completer = to_python(rl.completer)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
ev, line = self.to_repl.get()
|
ev, line = self.to_repl.get()
|
||||||
try:
|
try:
|
||||||
@ -261,12 +271,11 @@ class Repl(Thread):
|
|||||||
elif ev == 'line':
|
elif ev == 'line':
|
||||||
rl.send_line(line)
|
rl.send_line(line)
|
||||||
else:
|
else:
|
||||||
val = rl.completer(line)
|
val = completer(line)
|
||||||
val = to_python(val)
|
val = to_python(val)
|
||||||
self.from_repl.put(val[0])
|
self.from_repl.put(val[0])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if 'JSError' in e.__class__.__name__:
|
if isinstance(e, JSError):
|
||||||
e = JSError(e) # A bare JSError
|
|
||||||
print (e.stack or e.message, file=sys.stderr)
|
print (e.stack or e.message, file=sys.stderr)
|
||||||
else:
|
else:
|
||||||
import traceback
|
import traceback
|
||||||
@ -290,7 +299,7 @@ class Repl(Thread):
|
|||||||
def completer(text, num):
|
def completer(text, num):
|
||||||
if self.completions is None:
|
if self.completions is None:
|
||||||
self.to_repl.put(('complete', text))
|
self.to_repl.put(('complete', text))
|
||||||
self.completions = self.from_repl.get()
|
self.completions = filter(None, self.get_from_repl())
|
||||||
if self.completions is None:
|
if self.completions is None:
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
@ -302,7 +311,7 @@ class Repl(Thread):
|
|||||||
self.readline.set_completer(completer)
|
self.readline.set_completer(completer)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
lw = self.from_repl.get()
|
lw = self.get_from_repl()
|
||||||
if lw is None:
|
if lw is None:
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
q = self.prompt
|
q = self.prompt
|
||||||
|
@ -24,7 +24,22 @@ exports.readFileSync = Duktape.readfile;
|
|||||||
'''
|
'''
|
||||||
vm = '''
|
vm = '''
|
||||||
exports.createContext = Duktape.create_context;
|
exports.createContext = Duktape.create_context;
|
||||||
exports.runInContext = Duktape.run_in_context;
|
exports.runInContext = function(code, ctx) {
|
||||||
|
var result = Duktape.run_in_context(code, ctx);
|
||||||
|
if (result[0]) return result[1];
|
||||||
|
var cls = Error;
|
||||||
|
var e = result[1];
|
||||||
|
if (e.name) {
|
||||||
|
try {
|
||||||
|
cls = eval(e.name);
|
||||||
|
} catch(e) {}
|
||||||
|
}
|
||||||
|
var err = cls(e.message);
|
||||||
|
err.fileName = e.fileName;
|
||||||
|
err.lineNumber = e.lineNumber;
|
||||||
|
err.stack = e.stack;
|
||||||
|
throw err;
|
||||||
|
};
|
||||||
'''
|
'''
|
||||||
path = '''
|
path = '''
|
||||||
exports.join = function () { return arguments[0] + '/' + arguments[1]; }
|
exports.join = function () { return arguments[0] + '/' + arguments[1]; }
|
||||||
@ -74,7 +89,13 @@ class Function(object):
|
|||||||
return str('[Function: %s(...) from file: %s]' % (x.name, x.fileName))
|
return str('[Function: %s(...) from file: %s]' % (x.name, x.fileName))
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
def __call__(self, *args, **kwargs):
|
||||||
return self.func(*args, **kwargs)
|
try:
|
||||||
|
return self.func(*args, **kwargs)
|
||||||
|
except dukpy.JSError as e:
|
||||||
|
self.reraise(e)
|
||||||
|
|
||||||
|
def reraise(self, e):
|
||||||
|
raise JSError(e), None, sys.exc_info()[2]
|
||||||
|
|
||||||
def to_python(x):
|
def to_python(x):
|
||||||
try:
|
try:
|
||||||
@ -113,6 +134,15 @@ class JSError(Exception):
|
|||||||
Exception.__init__(self, type('')(e))
|
Exception.__init__(self, type('')(e))
|
||||||
self.name = self.js_message = self.fileName = self.lineNumber = self.stack = None
|
self.name = self.js_message = self.fileName = self.lineNumber = self.stack = None
|
||||||
|
|
||||||
|
def as_dict(self):
|
||||||
|
return {
|
||||||
|
'name':self.name or undefined,
|
||||||
|
'message': self.js_message or self.message,
|
||||||
|
'fileName': self.fileName or undefined,
|
||||||
|
'lineNumber': self.lineNumber or undefined,
|
||||||
|
'stack': self.stack or undefined
|
||||||
|
}
|
||||||
|
|
||||||
contexts = {}
|
contexts = {}
|
||||||
|
|
||||||
def create_context(base_dirs, *args):
|
def create_context(base_dirs, *args):
|
||||||
@ -125,8 +155,12 @@ def create_context(base_dirs, *args):
|
|||||||
return key
|
return key
|
||||||
|
|
||||||
def run_in_context(code, ctx, options=None):
|
def run_in_context(code, ctx, options=None):
|
||||||
ans = contexts[ctx].eval(code)
|
c = contexts[ctx]
|
||||||
return to_python(ans)
|
try:
|
||||||
|
ans = c.eval(code)
|
||||||
|
except JSError as e:
|
||||||
|
return [False, e.as_dict()]
|
||||||
|
return [True, to_python(ans)]
|
||||||
|
|
||||||
class Context(object):
|
class Context(object):
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user