Script scripterng_runtime
|
|
1 """
2 This runtime module contains everything about running
3 Python and QtScript scripts inside Scribus.
4
5 Look at run_filename for details.
6 """
7 import os
8 import hashlib
9 from ConfigParser import ConfigParser
10
11 import sip
12 from PyQt4.QtCore import QThread, QObject, QVariant
13 from PyQt4.QtGui import qApp, QMessageBox
14 from PyQt4.QtScript import QScriptEngine, QScriptValue
15
16 from safe_eval import checkCode
17 import permitdlg
18
19 import __main__
20
21 from inspect import getargspec
24
25
26
27
28
29
31 ConfigParser.__init__(self)
32
33 path = os.path.expanduser("~/.scribus/scripterng")
34 if not os.path.exists(path):
35 os.makedirs(path)
36 self.filename = os.path.join(path, "runtime.cfg")
37 self.read([self.filename])
38
39
41 fp = open(self.filename, "w")
42 self.write(fp)
43 fp.close()
44
45
46 - def set(self, section, key, value):
47 if not self.has_section(section):
48 self.add_section(section)
49 ConfigParser.set(self, section, key, value)
50 self.save()
51
52
54 value = self.get(section, key).strip().lower()
55 if value and value in ["true", "on", "yes", "1"]:
56 return True
57 elif value and value in ["false", "off", "no", "0"]:
58 return False
59 else:
60 raise ValueError, "Invalid boolean value %r" % value
61
62
63 runtime_config = RuntimeConfig()
64
65 extension_namespace = __main__.__dict__
66
67
68 qts_engine = None
74
77 def wrapper(context, engine):
78 args = []
79 (fargs, fvarargs, fvarkw, fdefaults) = getargspec(func)
80 if len(fargs) and fargs[0] == "self":
81 args.append(context.thisObject())
82 for i in xrange(context.argumentCount()):
83 args.append(context.argument(i))
84 try:
85 result = func(*args)
86 except Exception, e:
87
88
89 return context.throwValue(QScriptValue(engine, str(e)))
90 if result:
91 return QScriptValue(engine, result)
92 else:
93 return QScriptValue()
94 return wrapper
95
96
97 @qts_func_decorator
98 -def alert(msg_qsv):
99 msg = msg_qsv.toString()
100 QMessageBox.information(ScripterNG.dialogs.mainWindow.qt, "Alert", msg)
101
104 go = engine.globalObject()
105 for name, value in ns.items():
106 if isinstance(value, QObject):
107 value = engine.newQObject(value)
108 elif callable(value):
109 value = engine.newFunction(value)
110
111
112 go.setProperty(name, value)
113
116 engine = QScriptEngine()
117 update_qs_namespace(engine,
118 {
119 "Application": qApp,
120 "ScripterNG": ScripterNG.qt,
121 "alert": alert
122 })
123 return engine
124
125
126 -def run_qtscript(filename, subroutine=None, extension=False):
127 global qts_engine
128 if not extension:
129 engine = newQScriptEngine()
130 else:
131 engine = qts_engine = qts_engine or newQScriptEngine()
132 code = open(filename).read()
133 engine.clearExceptions()
134 result = engine.evaluate(code)
135 engine.collectGarbage()
136 if not engine.hasUncaughtException() and subroutine:
137 sub = engine.globalObject().property(subroutine)
138 sub.call()
139 if engine.hasUncaughtException():
140 bt = engine.uncaughtExceptionBacktrace()
141 raise QtSRuntimeError("%s\nTraceback:\%s" % (
142 str(engine.uncaughtException().toString()),
143 "\n".join([" %s" % l for l in list(bt)])))
144
147
148 source = source or open(filename).read()
149 return "%s:%s:%s" % (
150 os.path.basename(filename), len(filename), hashlib.sha256(source).hexdigest())
151
154 filename = os.path.abspath(os.path.expanduser(filename))
155 path = os.path.dirname(filename)
156
157
158 if path == os.path.join(ScripterNG.path, "autoload"):
159 return True
160 code = open(filename).read()
161 h = hash_source(filename, code)
162 if runtime_config.has_option("permissions", h):
163 return runtime_config.getbool("permissions", h)
164
165 problems = checkCode(code)
166 if problems and len(problems) == 1 and isinstance(problems[0], SyntaxError):
167 return True
168 elif problems:
169 ok = permitdlg.ask(filename, problems)
170 if ok == -2:
171 runtime_config.set("permissions", h, False)
172 return False
173 elif ok == 2:
174 return False
175 elif ok == -1:
176 runtime_config.set("permissions", h, True)
177 elif ok == 1:
178 pass
179 else:
180 raise ValueError, "Inknown return code for permission dialog: %r" % ok
181 return True
182
183
184 -def run_python(filename, subroutine=None, extension=False):
185 if not extension:
186 namespace = {
187 __name__: "__scribus__",
188 __file__: filename
189 }
190 else:
191 namespace = extension_namespace
192 if not check_python(filename):
193 return
194 execfile(filename, namespace)
195 if subroutine:
196 sub = namespace[subroutine]
197 sub()
198 if not extension:
199 del namespace
200
201
202 threads = []
217
220 thread = RunThread(func, *args)
221 thread.start()
222
223 return thread
224
228 """
229 mark every child of ScripterNG.collector to keep
230 """
231 for child in ScripterNG.collector.children():
232 if hasattr(child, "qt"): child = child.qt
233 child.setProperty("keep", QVariant(True))
234
238 """
239 delete every child which is not marked as keep
240 """
241 for child in ScripterNG.collector.children():
242 if hasattr(child, "qt"): child = child.qt
243 v = child.property("keep")
244 if v and v.toBool() == True:
245
246 continue
247 print "* deleting collected", child
248 sip.delete(child)
249
250
251
252 -def run_filename(filename, subroutine=None, extension=False, background=False):
253 """
254 Call this function to run a script and nothing else.
255 It will do everything for you, including garbage collection
256 for QtScript (very simple implementation, see mark_keep and cleanup).
257 Running as extension uses the __main__ namespace and does not
258 delete objects after execution.
259 Running in background as a thread is not much tested and
260 should only be used for non-GUI scripts.
261 """
262 mark_keep()
263 if background:
264 run_func = run_background
265 else:
266 run_func = lambda func, *args: func(*args)
267 if filename.endswith((".sqts", ".qts", ".sjs", ".js")):
268 run_func(run_qtscript, filename, subroutine, extension)
269 else:
270 run_func(run_python, filename, subroutine, extension)
271 if not background and not extension:
272
273 cleanup()
274