fsleyes_props

fsleyes_props is a framework for event-driven programming using python descriptors, similar in functionality to, and influenced by Enthought Traits.

Example usage

>>> import fsleyes_props as props

>>> class PropObj(props.Props):
        myProperty = props.Boolean()

>>> myPropObj = PropObj()


# Access the property value as a normal attribute:
>>> myPropObj.myProperty = True
>>> myPropObj.myProperty
True


# access the props.Boolean instance:
>>> myPropObj.getProp('myProperty')
<props.prop.Boolean at 0x1045e2710>


# access the underlying props.PropertyValue object
>>> myPropObj.getPropVal('myProperty')
<props.prop.PropertyValue instance at 0x1047ef518>


# Receive notification of property value changes
>>> def myPropertyChanged(value, *args):
        print('New property value: {}'.format(value))

>>> myPropObj.addListener(
       'myProperty', 'myListener', myPropertyChanged)

>>> myPropObj.myProperty = False
New property value: False


# Remove a previously added listener
>>> myPropObj.removeListener('myListener')

Package structure

To use fsleyes_props, your first step will be to define a subclass of HasProperties (a.k.a. Props), which contains one or more PropertyBase class attributes (see the properties_types module for the available types).

Once you have an instance of your HasProperties class, you can then create a GUI for it using the functions defined in the build and widgets modules, and the GUI specification building blocks defined in the build_parts module. You can also generate a command-line interface using the functions defined in the cli module.

All of the classes and functions referred to above are available in the fsleyes_props namespace, so you only need to import fsleyes_props to access them. You will however need to call the initGUI() function if you want to use any of the GUI generation functionality, before they are made available at the fsleyes_props namespace level.

Boring overview

Lots of the code in this package is probably very confusing. First of all, you will need to understand python descriptors. Descriptors are a way of adding properties to python objects, and allowing them to be accessed as if they were just simple attributes of the object, but controlling the way that the attributes are accessed and assigned.

The following link provides a good overview, and contains the ideas which form the basis for the implementation in this package:

And if you’ve got 30 minutes, this video gives a very good introduction to descriptors:

A HasProperties subclass contains a collection of PropertyBase instances as class attributes. When an instance of the HasProperties class is created, a PropertyValue object is created for each of the PropertyBase instances (or a PropertyValueList for ListPropertyBase instances). Each of these PropertyValue instances encapsulates a single value, of any type (a PropertyValueList instance encapsulates multiple PropertyValue instances). Whenever this value changes, the PropertyValue instance notifies any registered listeners of the change.

Notification

Application code may be notified of property changes by registering a callback listener on a PropertyValue object, via the equivalent methods:

Such a listener will be notified of changes to the PropertyValue object managed by the PropertyBase object, and associated with the HasProperties instance. For ListPropertyBase properties, a listener registered through one of the above methods will be notified of changes to the entire list. Alternately, a listener may be registered with individual items contained in the list (see PropertyValueList.getPropertyValueList()).

Validation

When a PropertyValue accepts a new value, it passes the value to the PropertyBase.validate() method of its parent PropertyBase instance to determine whether the new value is valid. The PropertyValue object may allow its underlying value to be set to something invalid, but it will tell registered listeners whether the new value is valid or invalid. PropertyValue objects can alternately be configured to raise a ValueError on an attempt to set them to an invalid value, but this has some caveats - see the PropertyValue documentation. Finally, to make things more confusing, some PropertyBase types will configure their PropertyValue objects to perform implicit casts when the property value is set.

The default validation logic of most PropertyBase objects can be configured via attributes. For example, the Number property allows minval and maxval attributes to be set. These may be set via PropertyBase constructors, (i.e. when it is defined as a class attribute of a HasProperties definition), and may be queried and changed on individual HasProperties instances via the HasProperties.getAttribute()/HasProperties.setAttribute() methods; similarly named methods are also available on PropertyBase instances. Some PropertyBase classes provide additional convenience methods for accessing their attributes (e.g. :meth`.Choice.addChoice`).

Binding and Synchronisation

Properties from different HasProperties instances may be bound to each other, so that changes in one are propagated to the other - see the bindable module. Building on this is the syncable module and its SyncableHasProperties class, which allows a one-to-many (one parent, multiple children) synchronisation hierarchy to be maintained, whereby all the properties of a child instance are by default synchronised to those of the parent, and this synchronisation can be independently enabled/disabled for each property. To use this functionality, simply inherit from the SyncableHasProperties class instead of the HasProperties class.

API overview

Property types

The following classes are provided as building-blocks for your application code:

HasProperties

Base class for classes which contain PropertyBase instances.

SyncableHasProperties

An extension to the HasProperties class which supports parent-child relationships between instances.

Object

A property which encapsulates any value.

Boolean

A property which encapsulates a bool value.

Int

A Number which encapsulates an integer.

Real

A Number which encapsulates a floating point number.

Percentage

A Real property which represents a percentage.

String

A property which encapsulates a string.

FilePath

A property which represents a file or directory path.

Choice

A property which may only be set to one of a set of predefined values.

List

A property which represents a list of items, of another property type.

Colour

A property which represents a RGBA colour, stored as four floating point values in the range 0.0 - 1.0.

ColourMap

A property which encapsulates a matplotlib.colors.Colormap.

Bounds

A property which represents numeric bounds in any number of dimensions, as long as that number is no more than 4.

Point

A property which represents a point in some n-dimensional (up to 4) space.

Command line and string serialisation

The following functions are provided to manage command-line argument generation and parsing:

applyArguments

Apply arguments to a HasProperties instance.

addParserArguments

Adds arguments to the given argparse.ArgumentParser for the properties of the given HasProperties class or instance.

generateArguments

Given a HasProperties instance, generates a list of arguments which could be used to configure another instance in the same way.

The following functions are provided for serialisation/deserialisation of property values to/from strings (equivalent methods are also available on HasProperties instances):

serialise

Get the value of the named property from the given HasProperties instance, serialise it, and return the serialised string.

deserialise

Deserialise the given string, under the assumption that it is a serialised value of the named property from the given HasProperties instance.

GUI specification/generation

The following classes are provided for you to create GUI specifications:

ViewItem

Superclass for Widget, Button, Label and Group.

Button

Represents a button which, when clicked, will call a specified callback function.

Toggle

Represents a toggle widget of some sort (e.g. a check box, or a toggle button) which, when clicked, calls a specified callback function.

Label

Represents a static text label.

Widget

Represents a widget which is used to modify a property value.

Group

Represents a collection of other ViewItem objects.

NotebookGroup

A Group representing a GUI Notebook.

HGroup

A group representing a GUI panel, whose children are laid out horizontally.

VGroup

A group representing a GUI panel, whose children are laid out vertically.

If the initGUI() function is called, the following GUI-related functions will be made available in the fsleyes_props package namespace:

makeWidget

Given hasProps (a HasProperties instance), propName (the name of a property of hasProps), and parent, a GUI object, creates and returns a widget, or a panel containing widgets, which may be used to edit the property value.

makeListWidget

Creeates a widget for a specific value in the specified list property.

makeListWidgets

Creates a widget for every value in the given list property.

makeSyncWidget

Creates a button which controls synchronisation of the specified property on the given hasProps instance, with the corresponding property on its parent.

bindWidget

Binds the given widget to the specified property.

unbindWidget

Unbinds the given widget from the specified property, assumed to have been previously bound via the bindWidget() function.

bindListWidgets

Binds the given sequence of widgets to each of the values in the specified list property.

buildGUI

Builds a GUI interface which allows the properties of the given HasProperties object to be edited.

buildDialog

Convenience method which embeds the result of a call to buildGUI() in a wx.Dialog.

Miscellaneous

The suppress() module provides some context managers allowing notification of properties to be suppressed in a with statement.

fsleyes_props.initGUI()[source]

If you wish to use GUI generation functionality, calling this function will add the relevant functions to the fsleyes_props package namespace.