88 lines
2.6 KiB
Python
88 lines
2.6 KiB
Python
![]() |
import json
|
||
|
import contextlib
|
||
|
|
||
|
import execjs._exceptions as exceptions
|
||
|
from execjs._abstract_runtime import AbstractRuntime
|
||
|
from execjs._abstract_runtime_context import AbstractRuntimeContext
|
||
|
from execjs._misc import encode_unicode_codepoints
|
||
|
|
||
|
try:
|
||
|
import PyV8
|
||
|
except ImportError:
|
||
|
_pyv8_available = False
|
||
|
else:
|
||
|
_pyv8_available = True
|
||
|
|
||
|
|
||
|
class PyV8Runtime(AbstractRuntime):
|
||
|
'''Runtime to execute codes with PyV8.'''
|
||
|
def __init__(self):
|
||
|
pass
|
||
|
|
||
|
@property
|
||
|
def name(self):
|
||
|
return "PyV8"
|
||
|
|
||
|
def _compile(self, source, cwd=None):
|
||
|
return self.Context(source)
|
||
|
|
||
|
def is_available(self):
|
||
|
return _pyv8_available
|
||
|
|
||
|
class Context(AbstractRuntimeContext):
|
||
|
def __init__(self, source=""):
|
||
|
self._source = source
|
||
|
|
||
|
def is_available(self):
|
||
|
return _pyv8_available
|
||
|
|
||
|
def _exec_(self, source):
|
||
|
source = '''\
|
||
|
(function() {{
|
||
|
{0};
|
||
|
{1};
|
||
|
}})()'''.format(
|
||
|
encode_unicode_codepoints(self._source),
|
||
|
encode_unicode_codepoints(source)
|
||
|
)
|
||
|
source = str(source)
|
||
|
|
||
|
# backward compatibility
|
||
|
with contextlib.nested(PyV8.JSContext(), PyV8.JSEngine()) as (ctxt, engine):
|
||
|
js_errors = (PyV8.JSError, IndexError, ReferenceError, SyntaxError, TypeError)
|
||
|
try:
|
||
|
script = engine.compile(source)
|
||
|
except js_errors as e:
|
||
|
raise exceptions.RuntimeError(e)
|
||
|
try:
|
||
|
value = script.run()
|
||
|
except js_errors as e:
|
||
|
raise exceptions.ProgramError(e)
|
||
|
return self.convert(value)
|
||
|
|
||
|
def _eval(self, source):
|
||
|
return self.exec_('return ' + encode_unicode_codepoints(source))
|
||
|
|
||
|
def _call(self, identifier, *args):
|
||
|
args = json.dumps(args)
|
||
|
return self.eval("{identifier}.apply(this, {args})".format(identifier=identifier, args=args))
|
||
|
|
||
|
@classmethod
|
||
|
def convert(cls, obj):
|
||
|
from PyV8 import _PyV8
|
||
|
if isinstance(obj, bytes):
|
||
|
return obj.decode('utf8')
|
||
|
if isinstance(obj, _PyV8.JSArray):
|
||
|
return [cls.convert(v) for v in obj]
|
||
|
elif isinstance(obj, _PyV8.JSFunction):
|
||
|
return None
|
||
|
elif isinstance(obj, _PyV8.JSObject):
|
||
|
ret = {}
|
||
|
for k in obj.keys():
|
||
|
v = cls.convert(obj[k])
|
||
|
if v is not None:
|
||
|
ret[cls.convert(k)] = v
|
||
|
return ret
|
||
|
else:
|
||
|
return obj
|