1
from PyQt4.QtScript import QScriptEngine, QScriptValue, QScriptValueIterator
5
from collections.abc import Mapping, Iterable
7
from collections import Mapping, Iterable
9
def iter_js_obj(js_obj):
10
"""QScriptValueIterator to python iterator emitting tuples of (str, QScriptValue)"""
11
it = QScriptValueIterator(js_obj)
15
yield (it.name(), it.value())
18
def iter_js_arr(js_arr):
19
"""iterate array in order"""
20
length = js_arr.property('length').toUInt32()
22
for i in range(length):
23
yield js_arr.property(i)
26
class PyJSEngine(QScriptEngine):
27
def py2js(self, py_obj):
28
"""python object to QScriptValue"""
29
if isinstance(py_obj, Mapping):
31
for name, value in py_obj.items():
32
ob.setProperty(name, self.py2js(value))
34
elif isinstance(py_obj, Iterable) and not isinstance(py_obj, str):
36
for i, item in enumerate(py_obj):
37
a.setProperty(i, self.py2js(item))
39
return QScriptValue(self, py_obj)
41
def js_call(self, js_function):
42
"""js function to python function acting on python types, returning a python type"""
44
js_val = js_function.call(self.globalObject(), self.py2js(args))
45
return js_val.toVariant()
50
"""Loads a JSModule from filepath into engine"""
51
def __init__(self, engine, filepath, objname):
54
with open(filepath) as s:
55
code = fix_js(s.read())
57
self.engine.evaluate(code, s.name)
58
if self.engine.hasUncaughtException():
59
raise ValueError('file can’t be evaluated', self.engine.uncaughtException().toVariant())
61
self.obj = self.engine.globalObject().property(objname)
63
def __call__(self, *args):
64
call = self.engine.js_call(self.obj)
67
def __getitem__(self, key):
68
value = self.obj.property(key)
69
if value.isFunction():
70
return self.engine.js_call(value)
71
return value.toVariant()
74
# some ECMAScript ReservedWords which can be used as object property names.
75
_keywords = 'continue|break|function|var|delete|if|then|else' # extend as appropriate
76
_keyword_in_okey = re.compile(r'\b({})\s*:'.format(_keywords))
77
_keyword_in_attr = re.compile(r'\.({})\b'.format(_keywords))
81
"""Fixes JS so that Qt’s engine can digest it.
83
The problem is that unquoted object keys like `{key: 'value'}`,
84
as well as member accessors like `object.member` may be IdentifierNames,
85
while Qt’s implementation expects them not to be ReservedWords.
87
>>> fix_js('var foo = { function: function() {} }')
88
'{ "function": function() {} }'
89
>>> fix_js('foo.function()')
92
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.6
93
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.5
94
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.1
96
code = _keyword_in_okey.sub(r'"\1":', code)
97
code = _keyword_in_attr.sub(r'["\1"]', code)
101
if __name__ == '__main__':
103
from pprint import pprint
104
from PyQt4.QtGui import QApplication
106
app = QApplication(sys.argv)
110
JSLint = JSModule(se, 'fulljslint.js', 'JSLINT')
112
with open(sys.argv[1]) as s:
113
lint_ok = JSLint(s.read(), {})
118
errors = JSLint['errors']
b'\\ No newline at end of file'