mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 10:14:46 -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 functools import partial
|
||||
from threading import Thread
|
||||
from Queue import Queue
|
||||
from Queue import Queue, Empty
|
||||
|
||||
from duktape import Context, JSError, to_python
|
||||
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
|
||||
}
|
||||
|
||||
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):
|
||||
self.init_ctx()
|
||||
rl = None
|
||||
@ -252,6 +260,8 @@ class Repl(Thread):
|
||||
''')
|
||||
rl = self.ctx.g.rl
|
||||
self.ctx.eval('module.exports(repl_options)')
|
||||
completer = to_python(rl.completer)
|
||||
|
||||
while True:
|
||||
ev, line = self.to_repl.get()
|
||||
try:
|
||||
@ -261,12 +271,11 @@ class Repl(Thread):
|
||||
elif ev == 'line':
|
||||
rl.send_line(line)
|
||||
else:
|
||||
val = rl.completer(line)
|
||||
val = completer(line)
|
||||
val = to_python(val)
|
||||
self.from_repl.put(val[0])
|
||||
except Exception as e:
|
||||
if 'JSError' in e.__class__.__name__:
|
||||
e = JSError(e) # A bare JSError
|
||||
if isinstance(e, JSError):
|
||||
print (e.stack or e.message, file=sys.stderr)
|
||||
else:
|
||||
import traceback
|
||||
@ -290,7 +299,7 @@ class Repl(Thread):
|
||||
def completer(text, num):
|
||||
if self.completions is None:
|
||||
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:
|
||||
return None
|
||||
try:
|
||||
@ -302,7 +311,7 @@ class Repl(Thread):
|
||||
self.readline.set_completer(completer)
|
||||
|
||||
while True:
|
||||
lw = self.from_repl.get()
|
||||
lw = self.get_from_repl()
|
||||
if lw is None:
|
||||
raise SystemExit(1)
|
||||
q = self.prompt
|
||||
|
@ -24,7 +24,22 @@ exports.readFileSync = Duktape.readfile;
|
||||
'''
|
||||
vm = '''
|
||||
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 = '''
|
||||
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))
|
||||
|
||||
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):
|
||||
try:
|
||||
@ -113,6 +134,15 @@ class JSError(Exception):
|
||||
Exception.__init__(self, type('')(e))
|
||||
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 = {}
|
||||
|
||||
def create_context(base_dirs, *args):
|
||||
@ -125,8 +155,12 @@ def create_context(base_dirs, *args):
|
||||
return key
|
||||
|
||||
def run_in_context(code, ctx, options=None):
|
||||
ans = contexts[ctx].eval(code)
|
||||
return to_python(ans)
|
||||
c = contexts[ctx]
|
||||
try:
|
||||
ans = c.eval(code)
|
||||
except JSError as e:
|
||||
return [False, e.as_dict()]
|
||||
return [True, to_python(ans)]
|
||||
|
||||
class Context(object):
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user