Merge lp:~kissiel/checkbox/use-pyotherside1.4 into lp:checkbox
- use-pyotherside1.4
- Merge into trunk
Proposed by
Maciej Kisielewski
Status: | Merged |
---|---|
Approved by: | Zygmunt Krynicki |
Approved revision: | 3814 |
Merged at revision: | 3813 |
Proposed branch: | lp:~kissiel/checkbox/use-pyotherside1.4 |
Merge into: | lp:checkbox |
Diff against target: |
417 lines (+97/-193) 6 files modified
checkbox-touch/checkbox-touch.qml (+3/-7) checkbox-touch/components/CheckboxTouchApplication.qml (+5/-4) checkbox-touch/components/PythonLogger.qml (+13/-7) checkbox-touch/components/PythonObjectHandle.qml (+0/-76) checkbox-touch/components/PythonObjectRef.qml (+69/-0) checkbox-touch/py/checkbox_touch.py (+7/-99) |
To merge this branch: | bzr merge lp:~kissiel/checkbox/use-pyotherside1.4 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Zygmunt Krynicki (community) | Approve | ||
Review via email: mp+260106@code.launchpad.net |
Commit message
Description of the change
Migration from PythonObjectHandle to PythonObjectRef (pyotherside-1.4)
To post a comment you must log in.
- 3811. By Maciej Kisielewski
-
checkbox-touch: add PythonObjectRef component
This patch adds qml component that handles referencing python objects from qml
side.Signed-off-by: Maciej Kisielewski <email address hidden>
- 3812. By Maciej Kisielewski
-
checkbox-touch: migrate CheckboxTouchAp
plication class to PythonObjectRef This patch moves main CheckboxTouchAp
plication class to be used through
PythonObjectRef from QML side. - 3813. By Maciej Kisielewski
-
checkbox-touch: migrate PythonLogger to PythonObjectRef
Signed-off-by: Maciej Kisielewski <email address hidden>
- 3814. By Maciej Kisielewski
-
checkbox-touch: remove PythonObjectHandle
Signed-off-by: Maciej Kisielewski <email address hidden>
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'checkbox-touch/checkbox-touch.qml' |
2 | --- checkbox-touch/checkbox-touch.qml 2015-05-20 07:56:01 +0000 |
3 | +++ checkbox-touch/checkbox-touch.qml 2015-05-27 06:52:22 +0000 |
4 | @@ -23,7 +23,7 @@ |
5 | import Ubuntu.Components 1.1 |
6 | import Ubuntu.Components.Popups 0.1 |
7 | import QtQuick.Layouts 1.1 |
8 | -import io.thp.pyotherside 1.2 |
9 | +import io.thp.pyotherside 1.4 |
10 | import "components" |
11 | import "components/ErrorLogic.js" as ErrorLogic |
12 | import "components/CbtDialogLogic.js" as CbtDialogLogic |
13 | @@ -110,9 +110,7 @@ |
14 | // create_app_object() function and assign the resulting handle |
15 | // back to the application component. |
16 | py.importModule("checkbox_touch", function() { |
17 | - call("checkbox_touch.create_app_object", [], function(handle) { |
18 | - app.handle = handle; |
19 | - }); |
20 | + app.construct("checkbox_touch.create_app_object", []) |
21 | }); |
22 | } |
23 | onError: { |
24 | @@ -146,9 +144,7 @@ |
25 | Component.onCompleted: { |
26 | py.Component.onCompleted.connect(function() { |
27 | py.importModule("checkbox_touch", function() { |
28 | - py.call("checkbox_touch.get_qml_logger", [], function(handle) { |
29 | - logger.handle = handle; |
30 | - }); |
31 | + construct("checkbox_touch.get_qml_logger", []); |
32 | }); |
33 | }); |
34 | } |
35 | |
36 | === modified file 'checkbox-touch/components/CheckboxTouchApplication.qml' |
37 | --- checkbox-touch/components/CheckboxTouchApplication.qml 2015-05-12 09:58:35 +0000 |
38 | +++ checkbox-touch/components/CheckboxTouchApplication.qml 2015-05-27 06:52:22 +0000 |
39 | @@ -1,10 +1,11 @@ |
40 | /* |
41 | * This file is part of Checkbox |
42 | * |
43 | - * Copyright 2014 Canonical Ltd. |
44 | + * Copyright 2014-2015 Canonical Ltd. |
45 | * |
46 | * Authors: |
47 | * - Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
48 | + * - Maciej Kisielewski <maciej.kisielewski@canonical.com> |
49 | * |
50 | * This program is free software; you can redistribute it and/or modify |
51 | * it under the terms of the GNU General Public License as published by |
52 | @@ -24,7 +25,7 @@ |
53 | import "ErrorLogic.js" as ErrorLogic |
54 | |
55 | |
56 | -PythonObjectHandle { |
57 | +PythonObjectRef { |
58 | id: app |
59 | // Version of the application |
60 | property string applicationVersion |
61 | @@ -37,7 +38,7 @@ |
62 | signal appReady(); |
63 | |
64 | // Signal sent when a session becomes ready |
65 | - signal sessionReady(); |
66 | + signal sessionReady() |
67 | |
68 | // Create a new session |
69 | // |
70 | @@ -168,7 +169,7 @@ |
71 | |
72 | // Internal handler that triggers a call to python to query for runtime and |
73 | // application versions. |
74 | - onHandleReady: { |
75 | + onObjectReady: { |
76 | request("get_version_pair", [], function(result) { |
77 | app.applicationVersion = result.application_version; |
78 | app.plainboxVersion = result.plainbox_version; |
79 | |
80 | === modified file 'checkbox-touch/components/PythonLogger.qml' |
81 | --- checkbox-touch/components/PythonLogger.qml 2015-02-09 14:19:45 +0000 |
82 | +++ checkbox-touch/components/PythonLogger.qml 2015-05-27 06:52:22 +0000 |
83 | @@ -20,7 +20,7 @@ |
84 | */ |
85 | |
86 | /*! \brief Python-driven logger |
87 | - \inherits PythonObjectHandle |
88 | + \inherits PythonObjectRef |
89 | |
90 | This component uses pyotherside to forward logging events to python. |
91 | It monkey-patches console.log and console.error to capture their calls |
92 | @@ -28,7 +28,8 @@ |
93 | */ |
94 | import QtQuick 2.0 |
95 | |
96 | -PythonObjectHandle { |
97 | +PythonObjectRef { |
98 | + id: pythonLogger |
99 | |
100 | function debug(msg) { |
101 | invoke('debug', [msg], function() {}); |
102 | @@ -63,13 +64,18 @@ |
103 | |
104 | /** Overridden invoke that doesn't log invoke calls */ |
105 | function invoke(func, args, callback) { |
106 | - if (py !== null && handle > 0) { |
107 | - py.call("py_invoke", [handle, func, args], function(response) { |
108 | + if (py !== null && object !== null) { |
109 | + var callable = py.getattr(object, func); |
110 | + if (!callable) { |
111 | + console.error("Unable to invoke " + func + " on python logger"); |
112 | + throw "trying to invoke not existing method" |
113 | + } |
114 | + py.call(callable, args, function(response) { |
115 | callback(response); |
116 | }); |
117 | } else { |
118 | - _original_console_error("unable to py_invoke: " + handle + ", " + func + ", " + JSON.stringify(args)); |
119 | - throw "py_invoke called without ready py and handle"; |
120 | + _original_console_error("unable to invoke " + func + " on python logger"); |
121 | + throw "invoke called without py initiated and/or object constructed"; |
122 | } |
123 | } |
124 | |
125 | @@ -79,7 +85,7 @@ |
126 | _original_console_error = console.error; |
127 | } |
128 | |
129 | - onHandleReady: { |
130 | + onObjectReady: { |
131 | /* monkey-patch console.log and console.error */ |
132 | console.log = function() { debug(_argsToString(arguments)); }; |
133 | console.error = function() { error(_argsToString(arguments)); }; |
134 | |
135 | === removed file 'checkbox-touch/components/PythonObjectHandle.qml' |
136 | --- checkbox-touch/components/PythonObjectHandle.qml 2014-09-29 19:18:47 +0000 |
137 | +++ checkbox-touch/components/PythonObjectHandle.qml 1970-01-01 00:00:00 +0000 |
138 | @@ -1,76 +0,0 @@ |
139 | -/* |
140 | - * This file is part of Checkbox |
141 | - * |
142 | - * Copyright 2014 Canonical Ltd. |
143 | - * |
144 | - * Authors: |
145 | - * - Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
146 | - * |
147 | - * This program is free software; you can redistribute it and/or modify |
148 | - * it under the terms of the GNU General Public License as published by |
149 | - * the Free Software Foundation; version 3. |
150 | - * |
151 | - * This program is distributed in the hope that it will be useful, |
152 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
153 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
154 | - * GNU General Public License for more details. |
155 | - * |
156 | - * You should have received a copy of the GNU General Public License |
157 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
158 | - */ |
159 | -import QtQuick 2.0 |
160 | - |
161 | - |
162 | -QtObject { |
163 | - // Reference to pyotherside's Python object |
164 | - property var py: null |
165 | - // Handle to a python object (via RemoteObjectLifecycleManager) |
166 | - // if it is < 0 then it is an error of some kind |
167 | - // if it is 0 (default) then the handle is just invalid |
168 | - // if it is > 0 then it represents a valid object handle |
169 | - property int handle: 0 |
170 | - // Flag set just prior to sending the handleReady() signal |
171 | - property bool _ready: false |
172 | - |
173 | - // Signal sent when the handle is initially assigned *and* py is already |
174 | - // assigned (so when the python object is ready to be interacted with) |
175 | - signal handleReady(); |
176 | - |
177 | - // Dereference the python object when we are shutting down |
178 | - Component.onDestruction: _unref() |
179 | - // Maybe send the handleReady signal (once) when handle is changed |
180 | - onHandleChanged: _maybeReady() |
181 | - // Maybe send the handleReady signal (once) when 'py' is changed |
182 | - onPyChanged: _maybeReady() |
183 | - |
184 | - /** Send the handleReady() signal (once) if both py and handle are ready */ |
185 | - function _maybeReady() { |
186 | - if (handle > 0 && py !== null && _ready == false) { |
187 | - _ready = true; |
188 | - handleReady() |
189 | - } |
190 | - } |
191 | - |
192 | - /** Dereference this object */ |
193 | - function _unref() { |
194 | - if (py !== null && handle > 0) { |
195 | - // console.log("py_unref: " + handle); |
196 | - py.call("py_unref", [handle]); |
197 | - handle = 0; |
198 | - } |
199 | - } |
200 | - |
201 | - /** Call a method on this object */ |
202 | - function invoke(func, args, callback) { |
203 | - if (py !== null && handle > 0) { |
204 | - console.log("py_invoke(" + handle + ", " + func + ", " + JSON.stringify(args) + ") ..."); |
205 | - py.call("py_invoke", [handle, func, args], function(response) { |
206 | - console.log("py_invoke(" + handle + ", " + func + ", " + JSON.stringify(args) + ") -> " + JSON.stringify(response)); |
207 | - callback(response); |
208 | - }); |
209 | - } else { |
210 | - console.error("unable to py_invoke: " + handle + ", " + func + ", " + JSON.stringify(args)); |
211 | - throw "py_invoke called without ready py and handle"; |
212 | - } |
213 | - } |
214 | -} |
215 | |
216 | === added file 'checkbox-touch/components/PythonObjectRef.qml' |
217 | --- checkbox-touch/components/PythonObjectRef.qml 1970-01-01 00:00:00 +0000 |
218 | +++ checkbox-touch/components/PythonObjectRef.qml 2015-05-27 06:52:22 +0000 |
219 | @@ -0,0 +1,69 @@ |
220 | +/* |
221 | + * This file is part of Checkbox |
222 | + * |
223 | + * Copyright 2015 Canonical Ltd. |
224 | + * |
225 | + * Authors: |
226 | + * - Maciej Kisielewski <maciej.kisielewski@canonical.com> |
227 | + * |
228 | + * This program is free software; you can redistribute it and/or modify |
229 | + * it under the terms of the GNU General Public License as published by |
230 | + * the Free Software Foundation; version 3. |
231 | + * |
232 | + * This program is distributed in the hope that it will be useful, |
233 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
234 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
235 | + * GNU General Public License for more details. |
236 | + * |
237 | + * You should have received a copy of the GNU General Public License |
238 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
239 | + */ |
240 | +import QtQuick 2.0 |
241 | + |
242 | + |
243 | +QtObject { |
244 | + id: pythonObjectRef |
245 | + |
246 | + // Reference to pyotherside's Python object |
247 | + property var py: null |
248 | + |
249 | + // PyObjectRef to the object |
250 | + property var object: null |
251 | + |
252 | + // Signal sent when the object reference is ready to use |
253 | + signal objectReady() |
254 | + |
255 | + // Creation method name that were used to get the reference to the object |
256 | + property var creationMethodName: null |
257 | + |
258 | + function construct(creationMethodName, args) { |
259 | + if (!py) { |
260 | + console.error("Trying to get reference to python object without py initiated!"); |
261 | + } else { |
262 | + console.info("Getting reference to python object via " + creationMethodName); |
263 | + py.call(creationMethodName, args, function(result) { |
264 | + object = result; |
265 | + pythonObjectRef.creationMethodName = creationMethodName; |
266 | + objectReady(); |
267 | + }); |
268 | + } |
269 | + } |
270 | + /** Call a method on this object */ |
271 | + function invoke(func, args, callback) { |
272 | + if (py !== null && object !== null) { |
273 | + console.log("invoking " + func + " on object created with" + pythonObjectRef.creationMethodName + ", with args: " + JSON.stringify(args) + " ..."); |
274 | + var callable = py.getattr(object, func); |
275 | + if (!callable) { |
276 | + console.log("Unable to invoke " + func + " on object " + JSON.stringify(pythonObjectRef)); |
277 | + throw "trying to invoke inexistent method" |
278 | + } |
279 | + py.call(callable, args, function(response) { |
280 | + console.log(func + " on object created with" + pythonObjectRef.creationMethodName + ", with args: " + JSON.stringify(args) + " returned: " + JSON.stringify(response)); |
281 | + callback(response); |
282 | + }); |
283 | + } else { |
284 | + console.error("Unable to invoke " + func + " on object " + JSON.stringify(pythonObjectRef)); |
285 | + throw "invoke called without py initiated and/or object constructed"; |
286 | + } |
287 | + } |
288 | +} |
289 | |
290 | === modified file 'checkbox-touch/py/checkbox_touch.py' |
291 | --- checkbox-touch/py/checkbox_touch.py 2015-05-18 11:20:02 +0000 |
292 | +++ checkbox-touch/py/checkbox_touch.py 2015-05-27 06:52:22 +0000 |
293 | @@ -65,72 +65,9 @@ |
294 | from embedded_providers import EmbeddedProvider1PlugInCollection |
295 | |
296 | _logger = logging.getLogger('checkbox.touch') |
297 | -_manager = None |
298 | - |
299 | - |
300 | -class VerboseLifecycle: |
301 | - """ |
302 | - Mix-in class for verbose lifecycle reporting |
303 | - """ |
304 | - |
305 | - def __new__(cls, *args, **kwargs): |
306 | - self = super().__new__(cls, *args, **kwargs) |
307 | - _logger.debug("new %s %x", cls.__name__, id(self)) |
308 | - return self |
309 | - |
310 | - def __del__(self): |
311 | - _logger.debug("del %s %x", self.__class__.__name__, id(self)) |
312 | - |
313 | - |
314 | -class RemoteObjectLifecycleManager(VerboseLifecycle): |
315 | - """ |
316 | - Remote object life-cycle manager |
317 | - |
318 | - This class aids in handling non-trivial objects that are referenced from |
319 | - QML (via pyotherside) but really stored on the python side. |
320 | - """ |
321 | - |
322 | - def __init__(self): |
323 | - self._count = 0 |
324 | - self._handle_map = {} |
325 | - |
326 | - def unref(self, handle: int): |
327 | - """ |
328 | - Remove a reference represented by the specified handle |
329 | - """ |
330 | - _logger.debug("unref %s", handle) |
331 | - del self._handle_map[handle] |
332 | - |
333 | - def ref(self, obj: object) -> int: |
334 | - """ |
335 | - Store a reference to an object and return the handle |
336 | - """ |
337 | - self._count += 1 |
338 | - handle = self._count |
339 | - self._handle_map[handle] = obj |
340 | - _logger.debug("ref %r -> %s", obj, handle) |
341 | - return handle |
342 | - |
343 | - def invoke(self, handle: int, func: str, args): |
344 | - """ |
345 | - Call a method on a object represented by the handle |
346 | - |
347 | - :param handle: |
348 | - A (numeric) handle to the objecet |
349 | - :param func: |
350 | - The (name of the) function to call |
351 | - :param args: |
352 | - A list of positional arguments to pass |
353 | - :returns: |
354 | - The value returned by the called method |
355 | - """ |
356 | - obj = self._handle_map[handle] |
357 | - impl = getattr(obj, func) |
358 | - retval = impl(*args) |
359 | - return retval |
360 | - |
361 | - |
362 | -class PlainboxApplication(VerboseLifecycle, metaclass=abc.ABCMeta): |
363 | + |
364 | + |
365 | +class PlainboxApplication(metaclass=abc.ABCMeta): |
366 | """ |
367 | Base class for plainbox-based applications. |
368 | |
369 | @@ -141,16 +78,6 @@ |
370 | def __repr__(self): |
371 | return "<{}>".format(self.__class__.__name__) |
372 | |
373 | - @classmethod |
374 | - def create_and_get_handle(cls): |
375 | - """ |
376 | - Create an instance of the high-level PlainBox object |
377 | - |
378 | - :returns: |
379 | - A handle to a fresh instance of :class:`PlainBox` |
380 | - """ |
381 | - return _manager.ref(cls()) |
382 | - |
383 | @abc.abstractmethod |
384 | def get_version_pair(self): |
385 | """ |
386 | @@ -820,27 +747,8 @@ |
387 | self._password = password |
388 | |
389 | |
390 | -def bootstrap(): |
391 | - logging.basicConfig(level=logging.INFO, stream=sys.stderr) |
392 | - logging.info("environ: %r", os.environ) |
393 | - logging.info("path: %r", sys.path) |
394 | - # from plainbox.impl.logging import adjust_logging |
395 | - # from plainbox.impl.logging import setup_logging |
396 | - # Setup logging |
397 | - # setup_logging() |
398 | - # adjust_logging(logging.DEBUG, ['checkbox.stack'], True) |
399 | - # Create the Javascript <=> Python remote object lifecycle manager |
400 | - manager = RemoteObjectLifecycleManager() |
401 | - # Expose top-level functions for pyotherside's simplicity |
402 | - builtins.py_ref = manager.ref |
403 | - builtins.py_unref = manager.unref |
404 | - builtins.py_invoke = manager.invoke |
405 | - return manager |
406 | - |
407 | - |
408 | def get_qml_logger(): |
409 | - return _manager.ref(logging.getLogger('checkbox.touch.qml')) |
410 | - |
411 | - |
412 | -create_app_object = CheckboxTouchApplication.create_and_get_handle |
413 | -_manager = bootstrap() |
414 | + return logging.getLogger('checkbox.touch.qml') |
415 | + |
416 | + |
417 | +create_app_object = CheckboxTouchApplication |
Looks good, thanks for changing this. +1