From 26b21c253164f3cf38be3b93cfb9b53ca040eacf Mon Sep 17 00:00:00 2001 From: Brian Knapp Date: Tue, 15 May 2012 21:41:15 -0500 Subject: [PATCH] reST docs do not generate errors on make html. Proxy behavior completed/tested. Lists and dicts now work. --- doc/autobuild.py | 1 + kivy/interactive.py | 75 +++++++++++++++++++++++++++++++-------------- 2 files changed, 53 insertions(+), 23 deletions(-) diff --git a/doc/autobuild.py b/doc/autobuild.py index c304c7282..36c901b62 100644 --- a/doc/autobuild.py +++ b/doc/autobuild.py @@ -46,6 +46,7 @@ import kivy.modules.recorder import kivy.network.urlrequest import kivy.support import kivy.input.recorder +import kivy.interactive from kivy.factory import Factory # force loading of all classes from factory diff --git a/kivy/interactive.py b/kivy/interactive.py index aff8211ef..65b525353 100644 --- a/kivy/interactive.py +++ b/kivy/interactive.py @@ -13,17 +13,6 @@ to an :class:`App` so that it can be prototyped and debugged interactively. application will work as intended, but specifically overriding methods such as :meth:`on_touch` dynamically leads to trouble. -.. WARNING:: - This module uses threading and object proxies to encapsulate the running - :class:`App`. Deadlocks and memory corruption can occur if making direct - references inside the thread without going through the provided proxy(s). - -.. TIP:: - All of the proxies used in the module store their referent in the - :attr:`_ref` attribute, which can be accessed directly if needed, such as for - getting doc strings. :func:`help` and :func:`type` will access the proxy, - not its referent. - Creating an InteractiveLauncher ------------------------------- @@ -38,7 +27,7 @@ instance to the :class:`InteractiveLauncher` constructor.:: def build(self): return Button(test='Hello Shell') - interactiveLauncher = InteractiveLauncher(MyApp()).run() + interactiveLauncher = InteractiveLauncher(MyApp().run() The script will return, allowing an interpreter shell to continue running and inspection or modification of the :class:`App` can be done safely through the @@ -85,6 +74,12 @@ operator and pressing 'tab.' Run this code in an Ipython shell:: # Erase artwork and start over i.root.canvas.clear() +.. NOTE:: + All of the proxies used in the module store their referent in the + :attr:`_ref` attribute, which can be accessed directly if needed, such as for + getting doc strings. :func:`help` and :func:`type` will access the proxy, + not its referent. + Directly Pausing the Application -------------------------------- @@ -94,7 +89,7 @@ references to :class:`EventLoop`'s 'safe' and 'confirmed' the application manually. :meth:`Interactive.safeIn()` will cause the applicaiton to pause and - :meth:`InteractiveLauncher.safeOut()` will internally allow a paused application + :meth:`InteractiveLauncher.safeOut()` will allow a paused application to continue running. This is potentially useful for scripting actions into functions that need the screen to update etc. @@ -105,6 +100,11 @@ to continue running. This is potentially useful for scripting actions into Adding Attributes Dynamically ----------------------------- +.. NOTE:: + This module uses threading and object proxies to encapsulate the running + :class:`App`. Deadlocks and memory corruption can occur if making direct + references inside the thread without going through the provided proxy(s). + The :class:`InteractiveLauncher` can have attributes added to it exactly like a normal object, and if these were created from outside the membrane, they will not be threadsafe because the external references to them in the python interpreter do @@ -173,12 +173,12 @@ class SafeMembrane(object): def isMethod(self, fn): return type(fn) is type(self.isMethod) - # the interpreter will report that all attributes are objects of class - # SafeProxy unless some effort is made. + """ Everything from this point on is just a series of thread-safing proxy + methods that make calls against _ref and threadsafe whenever data will be + written to or if a method will be called. """ def __repr__(self): return self._ref.__repr__() - # just in case _ref is a non-method and callable def __call__(self,*args,**kw): self.safeIn() r = self._ref(*args,**kw) @@ -198,8 +198,6 @@ class SafeMembrane(object): if self.isMethod(r): r = self.enSafen(r) return r - #if attr.startswith('__'): - # return r return SafeMembrane(r, self.safe, self.confirmed) def __setattr__(self,attr,val, osa=object.__setattr__): @@ -212,12 +210,43 @@ class SafeMembrane(object): self.safeIn() setattr(self._ref,attr,val) self.safeOut() - # TODO - # add some dictionary and list methods to prevent other avenues - # for non-threadsafe objects to leak into the user's shell - # see peak.util.proxies.AbstractProxy for a guide + def __delattr__(self,attr, oda=object.__delattr__): + self.safeIn() + delattr(self._ref,attr) + self.safeOut() + + def __nonzero__(self): + return bool(self._ref) + def __getitem__(self,arg): + return self._ref[arg] + + def __setitem__(self,arg,val): + self.safeIn() + self._ref[arg] = val + self.safeOut() + + def __delitem__(self,arg): + self.safeIn() + del self._ref[arg] + self.safeOut() + + def __getslice__(self,i,j): + return self._ref[i:j] + + def __setslice__(self,i,j,val): + self.safeIn() + self._ref[i:j] = val + self.safeOut() + + def __delslice__(self,i,j): + self.safeIn() + del self._ref[i:j] + self.safeOut() + + + class InteractiveLauncher(SafeMembrane): """ Proxy to an application instance that launches it in a thread and then returns and acts as a proxy to the application in the thread""" @@ -244,7 +273,7 @@ class InteractiveLauncher(SafeMembrane): EventLoop.quit = True self.thread.join() - #Act like the app instance before _ref is set + #Act like the app instance even before _ref is set def __repr__(self): return self.app.__repr__()