Quick search

Interactive launcher

New in version 1.3.0.

The InteractiveLauncher provides a user-friendly python shell interface to an App so that it can be prototyped and debugged interactively.

Note

The Kivy API intends for some functions to only be run once or before the main EventLoop has started. Methods that can normally be called during the course of an application will work as intended, but specifically overriding methods such as on_touch() dynamically leads to trouble.

Creating an InteractiveLauncher

Take your existing subclass of App (this can be production code) and pass an instance to the InteractiveLauncher constructor.:

from kivy.interactive import InteractiveLauncher
from kivy.app import App
from kivy.uix.button import Button

class MyApp(App):
    def build(self):
        return Button(test='Hello Shell')

launcher = InteractiveLauncher(MyApp())
launcher.run()

After pressing enter, the script will return. This allows the interpreter to continue running. Inspection or modification of the App can be done safely through the InteractiveLauncher instance or the provided SafeMembrane class instances.

Note

If you want to test this example, start Python without any file to have already an interpreter, and copy/paste all the lines. You’ll still have the interpreter at the end + the kivy application running.

Interactive Development

IPython provides a fast way to learn the Kivy API. The App instance and all of it’s attributes, including methods and the entire widget tree, can be quickly listed by using the ‘.’ operator and pressing ‘tab’. Try this code in an Ipython shell.:

from kivy.interactive import InteractiveLauncher
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Ellipse

class MyPaintWidget(Widget):
    def on_touch_down(self, touch):
        with self.canvas:
            Color(1, 1, 0)
            d = 30.
            Ellipse(pos=(touch.x - d/2, touch.y - d/2), size=(d, d))


class TestApp(App):
    def build(self):
        return Widget()


i = InteractiveLauncher(TestApp())
i.run()
i.       # press 'tab' to list attributes of the app
i.root.  # press 'tab' to list attributes of the root widget

# App is boring.  Attach a new widget!
i.root.add_widget(MyPaintWidget())

i.safeIn()
# The application is now blocked.
# Click on the screen several times.
i.safeOut()
# The clicks will show up now

# Erase artwork and start over
i.root.canvas.clear()

Note

All of the proxies used in the module store their referent in the _ref attribute, which can be accessed directly if needed, such as for getting doc strings. help() and type() will access the proxy, not its referent.

Directly Pausing the Application

Both the InteractiveLauncher and SafeMembrane hold internal references to the EventLoop‘s ‘safe’ and ‘confirmed’ threading.Event objects. You can use their safing methods to control the application manually.

SafeMembrane.safeIn() will cause the application to pause and SafeMembrane.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.

Note

The pausing is implemented via the Clocks' schedule_once() method and occurs before the start of each frame.

Adding Attributes Dynamically

Note

This module uses threading and object proxies to encapsulate the running App. Deadlocks and memory corruption can occur if making direct references inside the thread without going through the provided proxy(s).

The 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 not go through InteractiveLauncher’s membrane behavior, inherited from SafeMembrane.

To threadsafe these external references, simply assign them to SafeMembrane instances of themselves like so:

from kivy.interactive import SafeMembrane

interactiveLauncher.attribute = myNewObject
# myNewObject is unsafe
myNewObject = SafeMembrane(myNewObject)
# myNewObject is now safe.  Call at will.
myNewObject.method()

TODO

Unit tests, examples, and a better explanation of which methods are safe in a running application would be nice. All three would be excellent.

Could be re-written with a context-manager style i.e.:

with safe:
    foo()

Any use cases besides compacting code?

class kivy.interactive.SafeMembrane(ob, *args, **kwargs)[source]

Bases: object

This help is for a proxy object. Did you want help on the proxy’s referent instead? Try using help(<instance>._ref)

The SafeMembrane is a threadsafe proxy that also returns attributes as new thread-safe objects and makes thread-safe method calls, preventing thread-unsafe objects from leaking into the user’s environment.

safeIn()[source]

Provides a thread-safe entry point for interactive launching.

safeOut()[source]

Provides a thread-safe exit point for interactive launching.

class kivy.interactive.InteractiveLauncher(app=None, *args, **kwargs)[source]

Bases: kivy.interactive.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.