diff --git a/fsl/props/__init__.py b/fsl/props/__init__.py index 1927caf14a6f825357039b6d629727d0d068d5b5..8317f6ae9f862255007e04464767d290a2b15e98 100644 --- a/fsl/props/__init__.py +++ b/fsl/props/__init__.py @@ -4,13 +4,154 @@ # # Author: Paul McCarthy <pauldmccarthy@gmail.com> # +"""Python descriptor framework. + +Usage:: + + >>> import fsl.props as props + + >>> class PropObj(props.HasProperties): + >>> 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 + # (there are caveats for List properties): + >>> 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') + + +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 module: + + - http://nbviewer.ipython.org/urls/gist.github.com/\ +ChrisBeaumont/5758381/raw/descriptor_writeup.ipynb + +And if you've got 30 minutes, this video gives a very good +introduction to descriptors: + + - http://pyvideo.org/video/1760/encapsulation-with-descriptors + + +A :class:`~fsl.props.properties.HasProperties` subclass contains a +collection of :class:`~fsl.props.properties.PropertyBase` instances +as class attributes. When an instance of the +:class:`~fsl.props.properties.HasProperties` class is created, a +:class:`~fsl.props.properties_value.PropertyValue` object is created +for each of the :class:`~fsl.props.properties.PropertyBase` instances +(or a :class:`~fsl.props.properties_value.PropertyValueList` for +:class:`~fsl.props.properties.ListPropertyBase` instances). + + +Each of these :class:`~fsl.props.properties_value.PropertyValue` instances +encapsulates a single value, of any type (a +:class:`~fsl.props.properties_value.PropertyValueList` instance encapsulates +multiple :class:`~fsl.props.properties_value.PropertyValue` instances). +Whenever a variable value changes, the +:class:`~fsl.props.properties_value.PropertyValue` instance passes the new +value to the :meth:`~fsl.props.properties.PropertyBase.validate` method of its +parent :class:`~fsl.props.properties.PropertyBase` instance to determine +whether the new value is valid, and notifies any registered listeners of the +change. The :class:`~fsl.props.properties_value.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. :class:`~fsl.props.properties_value.PropertyValue` objects can +alternately be configured to raise a :exc:`ValueError` on an attempt to set +them to an invalid value, but this has some caveats - see the +:class:`~fsl.props.properties_value.PropertyValue` documentation. Finally, to +make things more confusing, some :class:`~fsl.props.properties.PropertyBase` +types will configure their :class:`~fsl.props.properties_value.PropertyValue` +objects to perform implicit casts when the property value is set. + + +The default validation logic of most +:class:`~fsl.props.properties.PropertyBase` objects can be configured via +'constraints'. For example, the :class:~fsl.props.properties_types.Number` +property allows 'minval' and 'maxval' constraints to be set. These may be set +via :class:`~fsl.props.properties.PropertyBase` constructors, (i.e. when it is +defined as a class attribute of a :class:`~fsl.props.properties.HasProperties` +definition), and may be queried and changed on individual +:class:`~fsl.props.properties.HasProperties` instances via the +:class:`~fsl.props.properties.HasProperties.getConstraint`/\ +:class:`~fsl.props.properties.HasProperties.setConstraint` methods, which are +available on both :class:`~fsl.props.properties.PropertyBase` and +:class:`~fsl.props.properties.HasProperties` objects. + + +Application code may be notified of property changes by registering a callback +listener on a :class:`~fsl.props.properties_value.PropertyValue` object, via +the equivalent methods: + + - :meth:`fsl.props.properties.HasProperties.addListener` + - :meth:`fsl.props.properties.PropertyBase.addListener` + - :meth:`fsl.props.properties_value.PropertyValue.addListener` + +Such a listener will be notified of changes to the +:class:`~fsl.props.properties_value.PropertyValue` object managed by the +:class:`~fsl.props.properties.PropertyBase` object, and associated with the +:class:`~fsl.props.properties.HasProperties` instance. For +:class:`~fsl.props.properties.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 +:meth:`~fsl.props.properties_value.PropertyValueList.getPropertyValueList`). +""" import logging log = logging.getLogger(__name__) +# Allow access to the individual properties +# modules for advanced/dangerous uses. +import properties +import properties_value +import properties_types +import widgets +import widgets_number +import widgets_bounds +import widgets_point +import widgets_list +import build +import cli + +# The 'public' props API starts here. from properties import ( PropertyBase, - HasProperties, + HasProperties) + +from properties_types import ( Boolean, Int, Real, diff --git a/fsl/props/properties.py b/fsl/props/properties.py index cd5596d2f968596d01589bcba678e3279cabdb06..9a530a0137e4f0c04afc64711d956e993a5765a9 100644 --- a/fsl/props/properties.py +++ b/fsl/props/properties.py @@ -1,157 +1,60 @@ #!/usr/bin/env python # -# properties.py - Python descriptors of various types. +# properties.py - Python descriptor framework. # -# This module should not be imported directly - import the fsl.props -# package instead. Property type definitions are in properties_types.py. -# -# Usage: -# -# >>> import fsl.props as props -# -# >>> class PropObj(props.HasProperties): -# >>> 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 -# # (there are caveats for List properties): -# >>> 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') -# -# -# Lots of the code in this file 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 module: -# -# - http://nbviewer.ipython.org/urls/gist.github.com/\ -# ChrisBeaumont/5758381/raw/descriptor_writeup.ipynb -# -# And if you've got 30 minutes, this video gives a very good -# introduction to descriptors: -# -# - http://pyvideo.org/video/1760/encapsulation-with-descriptors -# -# -# A HasProperties (sub)class contains a collection of PropertyBase instances -# as class attributes. When an instance of the HasProperties class is created, -# a PropertyValue(see properties_value.py) 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 a variable value changes, the PropertyValue instance -# passes the new value to the validate method of its parent PropertyBase -# instance to determine whether the new value is valid, and notifies any -# registered listeners of the change. 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.__init__ docstring. 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 'constraints'. For example, the Number property allows 'minval' and -# 'maxval' constraints 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 getConstraint/setConstraint methods, -# which are available on both PropertyBase and HasProperties objects. -# -# -# Application code may be notified of property changes by registering a -# callback listener on a PropertyValue object, via the equivalent methods: -# -# - HasProperties.addListener -# - PropertyBase.addListener -# - PropertyValue.addListener -# -# 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). -# -# -# author: Paul McCarthy <pauldmccarthy@gmail.com> +# Author: Paul McCarthy <pauldmccarthy@gmail.com> # +"""Python descriptor framework. + +This module defines the :class:`PropertyBase`, :class:`ListPropertyBase`, and +:class:`HasProperties` classes, which form the basis for defining class +properties. See also the :mod:`~fsl.props.properties_value` and +:mod:`~fsl.props.properties_types` modules. +""" import logging log = logging.getLogger(__name__) class InstanceData(object): + """An :class:`InstanceData` object is created for every :class:`PropertyBase` + object of a :class:`HasProperties` instance. It stores references to the + the instance and the associated property value(s). """ - An InstanceData object is created for every PropertyBase object of - a HasProperties instance. It stores references to the the instance - and the associated property value(s). - """ + def __init__(self, instance, propVal): self.instance = instance self.propVal = propVal class PropertyBase(object): - """ - The base class for properties. For every HasProperties object which - has this PropertyBase object as a property, one InstanceData object - is created and attached as an attribute of the parent. - - One important point to note is that a PropertyBase object may exist - without being bound to a HasProperties object (in which case it will - not create or manage a PropertyValue object). This is useful if you - just want validation functionality via the validate(), getConstraint() - and setConstraint() methods, passing in None for the instance - parameter. Nothing else will work properly though. + """The base class for properties. + + For every :class:`HasProperties` object which has this + :class:`PropertyBase` object as a property, one :class:`InstanceData` + object is created and attached as an attribute of the + :class:`HasProperties` object. + + One important point to note is that a :class:`PropertyBase` object may + exist without being bound to a :class:`HasProperties` object (in which + case it will not create or manage any + :class:`~fsl.props.properties_value.PropertyValue` objects). This is + useful if you just want validation functionality via the :meth:`validate`, + :meth:`getConstraint` and :meth:`setConstraint` methods, passing in + ``None`` for the instance parameter. Nothing else will work properly + though. Subclasses should: - - Ensure that PropertyBase.__init__ is called. + - Ensure that the superclass :meth:`__init__` is called. + + - Override the :meth:`validate` method to implement any built in + validation rules, ensuring that the the superclass implementation + is called first. - - Override the validate method to implement any built in - validation rules, ensuring that the PropertyBase.validate - method is called first. + - Override the :meth:`cast` method for implicit casting/conversion logic + (see :class:`~fsl.props.properties_types.Boolean` for an example). - - Override the cast method for implicit casting/conversion logic - (see properties_types.Boolean for an example). """ def __init__(self, @@ -161,37 +64,39 @@ class PropertyBase(object): required=False, allowInvalid=True, **constraints): - """ - Parameters (all optional): + """Define a :class:`PropertyBase` property. - - default: Default/initial value. + :param default: Default/initial value. - - required: Boolean determining whether or not this - property must have a value. May alternately - be a function which accepts one parameter, - the owning HasProperties instance, and - returns True or False. + :param bool required: Boolean determining whether or not this + property must have a value. May alternately + be a function which accepts one parameter, + the owning :class:`HasProperties` instance, + and returns ``True`` or ``False``. - - validateFunc: Custom validation function. Must accept - three parameters: a reference to the - HasProperties instance, the owner of - this property; a dictionary containing the - constraints for this property; and the new - property value. Should return True if the - property value is valid, False otherwise. + :param validateFunc: Custom validation function. Must accept + three parameters: a reference to the + :class:`HasProperties` instance, the owner + of this property; a dictionary containing + the constraints for this property; and the + new property value. Should return ``True`` + if the property value is valid, ``False`` + otherwise. - - preNotifyFunc: Function to be called whenever the property - value(s) changes. See PropertyValue.__init__. + :param preNotifyFunc: Function to be called whenever the property + value(s) changes. See + :class:`~fsl.props.properties_value.PropertyValue`. - - allowInvalid: If False, a ValueError will be raised on - all attempts to set this property to an - invalid value. This does not guarantee that - the property value will never be invalid - - see caveats in PropertyValue.__init__ - docstring. + :param bool allowInvalid: If ``False``, a :exc:`ValueError` will be + raised on all attempts to set this property + to an invalid value. This does not guarantee + that the property value will never be + invalid - see caveats in the + :class:`~fsl.props.properties_value.PropertyValue`. + documentation. - - constraints: Type specific constraints used to test - validity. + :param constraints: Type specific constraints used to test + validity. """ # The _label attribute is set by the PropertyOwner @@ -206,17 +111,17 @@ class PropertyBase(object): def addListener(self, instance, name, callback): - """ - Register a listener with this the PropertyValue object managed by this - property. + """Register a listener with the + :class:`~fsl.props.properties_value.PropertyValue` object managed by + this property. """ self._getInstanceData(instance).propVal.addListener(name, callback) def removeListener(self, instance, name): - """ - De-register the named listener from the PropertyValue object managed - by this property. + """De-register the named listener from the + :class:`~fsl.props.properties_value.PropertyValue` object managed by + this property. """ instData = self._getInstanceData(instance) @@ -225,9 +130,8 @@ class PropertyBase(object): def setPreNotifyFunction(self, instance, preNotifyFunc): - """ - Sets the function to be called on property value changes, before - any registered listeners. + """Sets the function to be called on property value changes, before any + registered listeners. """ instData = self._getInstanceData(instance) @@ -238,23 +142,22 @@ class PropertyBase(object): def addConstraintListener(self, instance, name, listener): - """ - Add a listener which will be notified whenever any constraint on this - Property change. An AttributeError will be raised if instance is None. - The listener function must accept the following parameters: + """Add a listener which will be notified whenever any constraint on the + :class:`~fsl.props.properties_value.PropertyValue` object bound to the + given instance change. An :exc:`AttributeError` will be raised if + instance is ``None``. The listener function must accept the following + parameters: - - instance: The HasProperties instance - - constraint: The name of the constraint that changed - - value: The new constraint value + - ``instance``: The :class:`HasProperties` instance + - ``constraint``: The name of the constraint that changed + - ``value``: The new constraint value """ instData = self._getInstanceData(instance) instData.propVal.addAttributeListener(name, listener) def removeConstraintListener(self, instance, name): - """ - Removes the named constraint listener. - """ + """Removes the named constraint listener.""" instData = self._getInstanceData(instance) if instData is None: return @@ -262,9 +165,8 @@ class PropertyBase(object): def getConstraint(self, instance, constraint): - """ - Returns the value of the named constraint for the specified instance, - or the default constraint value if instance is None. + """Returns the value of the named constraint for the specified + instance, or the default constraint value if instance is ``None``. """ instData = self._getInstanceData(instance) @@ -273,9 +175,9 @@ class PropertyBase(object): def setConstraint(self, instance, constraint, value): - """ - Sets the value of the named constraint for the specified instance, - or the default value if instance is None. + """Sets the value of the named constraint for the specified instance, or the + default value if instance is ``None``. + """ log.debug('Changing {} constraint on {}: {} = {}'.format( self._label, @@ -295,10 +197,10 @@ class PropertyBase(object): def getPropVal(self, instance): - """ - Return the PropertyValue object(s) for this property, associated - with the given HasProperties instance, or None if there is no - value for the given instance. + """Return the :class:`~fsl.props.properties_value.PropertyValue` + object(s) for this property, associated with the given + :class:`HasProperties` instance, or ``None`` if there is no value + for the given instance. """ instData = self._getInstanceData(instance) if instData is None: return None @@ -306,21 +208,20 @@ class PropertyBase(object): def _getInstanceData(self, instance): - """ - Returns the InstanceData object for the given instance, or None - if there is no InstanceData for the given instance. An InstanceData - object, which provides a binding between a PropertyBase object and - a HasProperties instance, is created by that HasProperties - instance when it is created (see HasProperties.__new__). + """Returns the :class:`InstanceData` object for the given instance, or + ``None`` if there is no :class:`InstanceData` for the given + instance. An :class:`InstanceData` object, which provides a binding + between a :class:`PropertyBase` object and a :class:`HasProperties` + instance, is created by that :class:`HasProperties` instance when it + is created (see :meth:`HasProperties.__new__`). """ return instance.__dict__.get(self._label, None) def _makePropVal(self, instance): - """ - Creates and returns PropertyValue object for the given instance. - Subclasses which encapsulate multiple values should override this - method, and return a PropertyValueList object instead. + """Creates and returns a + :class:`~fsl.props.properties_value.PropertyValue object for the given + :class:HasProperties` instance. """ return PropertyValue(instance, name=self._label, @@ -334,10 +235,9 @@ class PropertyBase(object): def _valChanged(self, value, valid, instance): - """ - This function is called by PropertyValue objects which are - managed by this PropertyBase object. It notifies any listeners - which have been registered to this property of any value changes. + """This function is called by PropertyValue objects which are managed + by this PropertyBase object. It notifies any listeners which have been + registered to this property of any value changes. """ instData = self._getInstanceData(instance) @@ -363,28 +263,25 @@ class PropertyBase(object): def validate(self, instance, attributes, value): - """ - Called when an attempt is made to set the property value on - the given instance. The sole purpose of PropertyBase.validate - is to determine whether a given value is valid or invalid; it - should not do anything else. In particular, it should not - modify any other property values on the instance, as bad - things would happen. - - If the given value is invalid, subclass implementations - should raise a ValueError containing a useful message as to - why the value is invalid. Otherwise, they should not return - any value. The default implementation does nothing, unless - a custom validate function, and/or required=True, was passed - to the constructor. If required is True, and the value is - None, a ValueError is raised. If a custom validate function - was set, it is called and, if it returns False, a ValueError - is raised. It may also raise a ValueError of its own for - invalid values. - - Subclasses which override this method should therefore call - this superclass implementation in addition to performing - their own validation. + """Called when an attempt is made to set the property value on the + given instance. The sole purpose of :meth:`validate` is to determine + whether a given value is valid or invalid; it should not do anything + else. In particular, it should not modify any other property values + on the instance, as bad things will probably happen. + + If the given value is invalid, subclass implementations should raise a + :exc:`ValueError` containing a useful message as to why the value is + invalid. Otherwise, they should not return any value. The default + implementation does nothing, unless a custom validate function, and/or + ``required=True``, was passed to the constructor. If ``required`` is + ``True``, and the value is ``None``, a :exc:`ValueError` is raised. If + a custom validate function was set, it is called and, if it returns + False, a :exc:`ValueError` is raised. It may also raise a + :exc:`ValueError` of its own for invalid values. + + Subclasses which override this method should therefore call this + superclass implementation in addition to performing their own + validation. """ # a value is required @@ -406,19 +303,17 @@ class PropertyBase(object): def cast(self, instance, attributes, value): - """ - This method is called when a value is assigned to this PropertyBase - object through a HasProperties attribute access. The default - implementaton just returns the given value. Subclasses may override - this method to perform any required implicit casting or conversion - rules. + """This method is called when a value is assigned to this + :class:`PropertyBase` object through a :class:`HasProperties` + attribute access. The default implementaton just returns the given + value. Subclasses may override this method to perform any required + implicit casting or conversion rules. """ return value def revalidate(self, instance): - """ - Forces validation of this property value, for the current instance. + """Forces validation of this property value, for the current instance. This will result in any registered listeners being notified, but only if the validity of the value has changed. """ @@ -428,11 +323,11 @@ class PropertyBase(object): def __get__(self, instance, owner): - """ - If called on the HasProperties class, and not on an instance, - returns this PropertyBase object. Otherwise, returns the value - contained in the PropertyValue object which is attached - to the instance. + """If called on the :class:`HasProperties` class, and not on an + instance, returns this :class:`PropertyBase` object. Otherwise, + returns the value contained in the + :class:`~fsl.props.properties_value.PropertyValue` object which is + attached to the instance. """ if instance is None: @@ -443,9 +338,8 @@ class PropertyBase(object): def __set__(self, instance, value): - """ - Set the value of this property, as attached to the given - instance, to the given value. + """Set the value of this property, as attached to the given instance, + to the given value. """ propVal = self.getPropVal(instance) @@ -453,27 +347,27 @@ class PropertyBase(object): class ListPropertyBase(PropertyBase): - """ - PropertyBase for properties which encapsulate more than one value. + """A :class:`PropertyBase` for properties which encapsulate more than + one value. """ def __init__(self, listType, **kwargs): - """ - Parameters: - - listType: An unbound PropertyBase instance, defining the - type of value allowed in the list. This is optional; - if not provided, values of any type will be allowed - in the list, but no validation or casting will be - performed. + """Define a :class:`ListPropertyBase` property. + + :param listType: An unbound :class:`PropertyBase` instance, defining + the type of value allowed in the list. This is + optional; if not provided, values of any type will be + allowed in the list, but no validation or casting + will be performed. """ PropertyBase.__init__(self, **kwargs) self._listType = listType def _makePropVal(self, instance): - """ - Creates and returns a PropertyValueList object to be associated - with the given HasProperties instance. + """Creates and returns a + :class:`~fsl.props.properties_value.PropertyValueList` object to be + associated with the given :class:`HasProperties` instance. """ if self._listType is not None: @@ -501,9 +395,9 @@ class ListPropertyBase(PropertyBase): def getPropValList(self, instance): - """ - Returns the list of PropertyValue objects which represent - the items stored in this list. + """Returns the list of + :class:`~fsl.props.properties_value.PropertyValue` objects which + represent the items stored in this list. """ propVal = self.getPropVal(instance) if propVal is not None: return propVal.getPropertyValueList() @@ -511,35 +405,30 @@ class ListPropertyBase(PropertyBase): def addItemListener(self, instance, index, name, callback): - """ - Convenience method which adds a listener to the property - value object at the given index. + """Convenience method which adds a listener to the property value + object at the given index. """ self.getPropValList(instance)[index].addListener(name, callback) def removeItemListener(self, instance, index, name): - """ - Convenience method which removes the named listener from - the property value at the given index. + """Convenience method which removes the named listener from the + property value at the given index. """ pvl = self.getPropValList(instance) if pvl is not None: pvl[index].removeListener(name) def addItemConstraintListener(self, instance, index, name, listener): - """ - Convenience method which adds a constraint listener (actually an - attribute listener) to the PropertyValue object at the given - index. + """Convenience method which adds a constraint listener (actually an + attribute listener) to the PropertyValue object at the given index. """ self.getPropValList(instance)[index].addAttributeListener( name, listener) def removeItemConstraintListener(self, instance, index, name): - """ - Convenience method which removes the named constraint listener + """Convenience method which removes the named constraint listener from the property value at the given index. """ pvl = self.getPropValList(instance) @@ -547,11 +436,10 @@ class ListPropertyBase(PropertyBase): def getItemConstraint(self, instance, index, constraint): - """ - Convenience method which returns the specified constraint for the - property value at the given index. If instance is None, the index + """Convenience method which returns the specified constraint for the + property value at the given index. If instance is ``None``, the index is ignored, and the default list type constraint value is returned. - If no list type was specified for this list, an AttributeError + If no list type was specified for this list, an :exc:AttributeError` is raised. """ @@ -564,12 +452,11 @@ class ListPropertyBase(PropertyBase): def setItemConstraint(self, instance, index, constraint, value): - """ - Convenience method which sets the specified constraint to the + """Convenience method which sets the specified constraint to the specified value, for the property value at the given index. If - instance is None, the index is ignored, and the default list + instance is ``None``, the index is ignored, and the default list type constraint value is changed. If no list type was specified - for this list, an AttributeError is raised. + for this list, an :exc:`AttributeError` is raised. """ propVal = self.getPropVal(instance) @@ -581,9 +468,8 @@ class ListPropertyBase(PropertyBase): class PropertyOwner(type): - """ - Metaclass for classes which contain PropertyBase objects. Sets - PropertyBase labels from the corresponding class attribute names. + """Metaclass for classes which contain :class:`PropertyBase` objects. Sets + :class:`PropertyBase` labels from the corresponding class attribute names. """ def __new__(cls, name, bases, attrs): for n, v in attrs.items(): @@ -594,17 +480,16 @@ class PropertyOwner(type): class HasProperties(object): - """ - Base class for classes which contain PropertyBase objects. - All classes which contain PropertyBase objects must subclass - this class. + """Base class for classes which contain :class:`PropertyBase` objects. All + classes which contain :class:`PropertyBase` objects must subclass this + class. """ __metaclass__ = PropertyOwner def __new__(cls, *args, **kwargs): - """ - Here we create a new HasProperties instance, and loop through all - of its PropertyBase properties to ensure that they are initialised. + """Here we create a new :class:`HasProperties` instance, and loop + through all of its :class:`PropertyBase` properties to ensure that + they are initialised. """ instance = super(HasProperties, cls).__new__(cls, *args, **kwargs) @@ -638,10 +523,9 @@ class HasProperties(object): @classmethod def getAllProperties(cls): - """ - Returns two lists, the first containing the names of all - properties of this object, and the second containing the - corresponding PropertyBase objects. + """Returns two lists, the first containing the names of all properties + of this object, and the second containing the corresponding + :class:`PropertyBase` objects. """ propNames = dir(cls) @@ -656,103 +540,93 @@ class HasProperties(object): @classmethod def getProp(cls, propName): - """ - Return the PropertyBase object for the given property. - """ + """Return the :class:`PropertyBase` object for the given property.""" return getattr(cls, propName) def getPropVal(self, propName): - """ - Return the PropertyValue object(s) for the given property. + """Return the :class:`~fsl.props.properties_value.PropertyValue` + object(s) for the given property. """ return self.getProp(propName).getPropVal(self) def getConstraint(self, propName, constraint): - """ - Convenience method, returns the value of the named constraint for the - named property. See PropertyBase.setConstraint. + """Convenience method, returns the value of the named constraint for + the named property. See :meth:`PropertyBase.getConstraint`. """ return self.getProp(propName).getConstraint(self, constraint) def setConstraint(self, propName, constraint, value): - """ - Convenience method, sets the value of the named constraint for the - named property. See PropertyBase.setConstraint. + """Convenience method, sets the value of the named constraint for + the named property. See :meth:`PropertyBase.setConstraint`. """ return self.getProp(propName).setConstraint(self, constraint, value) def getItemConstraint(self, propName, index, constraint): - """ - Convenience method, returns the value of the named constraint for + """Convenience method, returns the value of the named constraint for the value at the specified index of the named list property. See - ListPropertyBase.getItemConstraint. If the named property is not - a list property, an AttributeError is raised. + :meth:`ListPropertyBase.getItemConstraint`. If the named property is + not a list property, an :exc:`AttributeError` is raised. """ return self.getProp(propName).getItemConstraint( self, index, constraint) def setItemConstraint(self, propName, index, constraint, value): - """ - Convenience method, sets the value of the named constraint for + """Convenience method, sets the value of the named constraint for the value at the specified index of the named list property. See - ListPropertyBase.setItemConstraint. If the named property is not - a list property, an AttributeError is raised. + :meth:`ListPropertyBase.setItemConstraint`. If the named property + is not a list property, an :exc:`AttributeError` is raised. + """ return self.getProp(propName).setItemConstraint( self, index, constraint, value) def setPreNotifyFunction(self, instance, preNotifyFunc): - """ - Convenience method, sets the pre-notify function. See - PropertyBase.setPreNotifyFunction. + """Convenience method, sets the pre-notify function. See + :meth:`PropertyBase.setPreNotifyFunction`. """ self.getProp().setPreNotifyFunction(preNotifyFunc) def addListener(self, propName, listenerName, callback): - """ - Convenience method, adds the specified listener to the specified - property. See PropertyBase.addListener. + """Convenience method, adds the specified listener to the specified + property. See :meth:`PropertyBase.addListener`. """ self.getProp(propName).addListener(self, listenerName, callback) def removeListener(self, propName, listenerName): - """ - Convenience method, removes the specified listener from the specified - property. See PropertyBase.addListener. + """Convenience method, removes the specified listener from the specified + property. See :meth:`PropertyBase.addListener`. """ self.getProp(propName).removeListener(self, listenerName) def addConstraintListener(self, propName, listenerName, callback): - """ - Convenience method, addsthe specified constraint listener to - the specified property. See PropertyBase.addConstraintListener. + """Convenience method, adds the specified constraint listener to the + specified property. See :meth:`PropertyBase.addConstraintListener`. """ self.getProp(propName).addConstraintListener( self, listenerName, callback) def removeConstraintListener(self, propName, listenerName): - """ - Convenience method, removes the specified constraint listener from - the specified property. See PropertyBase.removeConstraintListener. + """Convenience method, removes the specified constraint listener + from the specified property. See + :meth:`PropertyBase.removeConstraintListener`. """ self.getProp(propName).removeConstraintListener(self, listenerName) def isValid(self, propName): - """ - Returns True if the current value of the specified property - is valid, False otherwise. + """Returns ``True`` if the current value of the specified property is + valid, ``False`` otherwise. """ prop = self.getProp(propName) @@ -765,10 +639,9 @@ class HasProperties(object): def validateAll(self): - """ - Validates all of the properties of this HasProperties object. - A list of tuples is returned, with each tuple containing a - property name, and an associated error string. The error string + """Validates all of the properties of this :class:`HasProperties` + object. A list of tuples is returned, with each tuple containing + a property name, and an associated error string. The error string is a message about the property which failed validation. If all property values are valid, the returned list will be empty. """ @@ -791,9 +664,8 @@ class HasProperties(object): def __str__(self): - """ - Returns a multi-line string containing the names and values - of all the properties of this object. + """Returns a multi-line string containing the names and values of + all the properties of this object. """ clsname = self.__class__.__name__ @@ -813,6 +685,5 @@ class HasProperties(object): return '\n'.join(lines) - +from properties_value import * from properties_types import * -from properties_value import *