Pyface Applications

Pyface provides a collection of classes suitable for representing an application. Although the classes are principally designed to work with GUI-based applications, the base class Application class does not and so can be used as the basis for command-line or server applications with a shared codebase with a GUI application.

Additionally, the application classes are designed to be forward-compatible with Envisage application classes so applications developed using this framework can easily be refactored to take advantage of the Envisage’s plug-in extensibility if that should be required.

Application Interface

The core of the Application class’ API are three methods: Application.run(), Application.start(), and Application.stop(). The Application.run() method is the entry-point of the application, and performs the following steps:

  1. calls the Application.start() method to initialize the application’s state.

  2. if the start is successful, calls an internal Application._run() method which does the actual work (such as running the GUI event loop).

  3. when the Application._run() method returns, calls Application.stop() to release any resources used by the application and de-initialize as needed.

Subclasses of the base Application class will likely override all three of these methods, but pyface.gui_application.GUIApplication subclasses may be able to avoid having to touch them, depending on what addition resources they need to access.

In addition to these three methods, there is an Application.exit() method that can be called by code that wants to halt the application at that point. For the base class this simply raises an :py:class:ApplicationExit exception, but for event loop based classes it may instead call appropriate toolkit code to close open windows and stop the application event loop.

During this life-cycle, the application will emit various Traits events indicating the state that it is currently in. The sequence of events is normally Application.starting, Application.started Application.application_initialized, Application.stopping, and Application.stopped

In addition to the core methods and events, the Application class has some traits for metadata about the application, primarily the human-readable application name, a description of the application, and a globally unique application id. The application also has traits holding platform-dependent “home” and “user” directory paths, which by default are provided by traits.etsconfig which give reasonable platform-dependent results.

Application Example

A simple command-line application might look something like this:

import argparse
from pyface.application import Application
from traits.api import Str

class HelloApplication(Application):
    """ Simple application subclass that greets a location. """

    #: The location being greeted.
    location = Str("world")

    def _run(self):
        super()._run()
        print("Hello "+self.location)

def main():
    app = HelloApplication()

    parser = argparse.ArgumentParser(description=app.description)
    parser.add_argument('location', nargs='?', default=app.location,
                        help="the location to greet")
    parser.parse_args(namespace=app)

    app.run()

if __name__ == '__main__':
    main()

GUIApplication Interface

The GUIApplication subclass is the base class to use for Pyface-based GUI applications. This class invokes the Pyface toolkit’s event loop in the GUIApplication._run() method, and stops it in the GUIApplication._exit() method.

The class has code that tracks application windows through their lifecycle. The application has a list GUIApplication.windows of all known windows. Windows can be added to the list with the GUIApplication.add_window() method which also handles opening the window. Windows are automatically removed from the list when they are closed. In addition the class has a GUIApplication.create_window() method which by default calls the GUIApplication.window_factory attribute and handles setting titles, icons and sizing of the created windows. Windows created by GUIApplication.create_window() still need to be added to the application’s list of windows via GUIApplication.add_window().

The GUIApplication.start() method of the class must ensure that there is at least one open window by the point that the event loop starts, particularly with the WxPython backend. The default GUIApplication.start() method calls GUIApplication._create_windows() to perform the initial set-up of open windows. The default behaviour is to call the GUIApplication.create_windows() method and then add that window.

In most cases to use the base GUIApplication class, you will want to:

  • create a subclass of ApplicationWindow that at least overrides the _create_contents() method to create the desired user interface. Ideally this window should be able to work without needing an application, as this helps with reusability.

  • create a window factory function that taskes the application and arbitrary other keyword arguments and creates an instance of the ApplicationWindow subclass along with any additional application-dependent state that is required. This can include application-dependent menus, toolbars, etc. as well as other state injected by from application.

While the GUIApplication class can be used without subclassing, for complex applications it is likely that the a subclass will need to be used, and will likely override the start(), stop() and create_window() methods to perform additional application-specific customization.

GUIApplication Example

The following example shows how to build a simple but functional GUIApplication which provides an interactive Python shell. The application has two parts: a pyface.application_window.ApplicationWindow subclass which is responsible for creating the Python shell widget, and a window factory which is responsible for creating the windows and populating the menu bar.

The application window subclass looks like this:

from pyface.api import ApplicationWindow, PythonShell
from traits.api import Instance

class PythonShellWindow(ApplicationWindow):
    """ An application window that displays a simple Python shell. """

    #: The title of the window.
    title = "Python Shell"

    #: The Python shell widget to use.
    shell = Instance('pyface.i_python_shell.IPythonShell')

    def _create_contents(self, parent):
        """ Create the shell widget. """
        self.shell = PythonShell(parent)
        return self.shell.control

Note that we don’t (and shouldn’t) need the application to be available for this class to work - it is a perfectly good stand-alone class that can potentially be re-used in many different contexts.

While the GUI application window subclass looks like this:

from pyface.api import GUIApplication
from pyface.action.api import (
    AboutAction, CloseWindowAction, CreateWindowAction, ExitAction, Group,
    MenuBarManager, MenuManager
)
from python_shell_window import PythonShellWindow

def create_python_shell_window(application, **kwargs):
    window = PythonShellWindow()
    window.menu_bar_manager = MenuBarManager(
        MenuManager(
            Group(CreateWindowAction(application=application)),
            Group(
                CloseWindowAction(window=window),
                ExitAction(application=application),
            ),
            name='&File',
        ),
        MenuManager(
            AboutAction(application=application),
            name='&Help',
        )
    )
    return window

def main():
    app = GUIApplication(
        name="Python Shell",
        description="An example application that provides a Python shell.",
        icon='python_icon',
        logo='python_logo',
        window_factory=create_python_shell_window,
    )
    app.run()

if __name__ == '__main__':
    main()

A more complete version of this can be found in the Pyface examples.

TasksApplication Interface

The TasksApplication class works in a similar way to the GUIApplication class, but instead of the supplying a window factory, instead you provide one or more TaskFactory instances which provide information about the different Tasks that are available for each window.

In addition the TasksApplication has traits that hold extra application-specific SchemaAddition mechanism, and DockPane via factories for creating the dock panes.

A complete TasksApplication can be as simple as:

from pyface.tasks.api import TaskFactory, TasksApplication
from python_editor_task import PythonEditorTask

def main():
    app = TasksApplication(
        id="example_python_editor_application",
        name="Python Editor",
        description=(
            "An example Tasks application that provides a Python editor."
        ),
        icon='python_icon',
        logo='python_logo',
        task_factories=[
            TaskFactory(
                id='example.python_editor_task',
                name="Python Editor",
                factory=PythonEditorTask
            )
        ],
    )

    # invoke the mainloop
    app.run()

if __name__ == '__main__':
    main()

A more complete version of this can be found in the Pyface examples.