I want to implement an entity with 2 boolean attributes, and a
requirement is that these two attributes never have the same boolean
value (think of some kind of radio buttons).

Let's start with a simple schema example:

# in schema.pyclassMyEntity(EntityType):use_option1=Boolean(required=True,default=True)use_option2=Boolean(required=True,default=False)

So new entities will be conform to the spec.

To do this, you need two things:

a constraint in the entity schema which will ring if both attributes
have the same value

a hook which will toggle the other attribute when one attribute is
changed.

RQL constraints are generally meant to be used on relations, but you
can use them on attributes too. Simply use 'S' to denote the entity,
and write the constraint normally. You need to have the same constraint on both attributes, because the constraint evaluation is triggered by the modification of the attribute.

With this update, it is no longer possible to have both options set to
True or False (you will get a ValidationError). The nice thing to
have is to get the other option to be updated when one of the two
attributes is changed, which means that you don't have to take care of
this when editing the entity in the web interface (which you cannot do
anyway if you are using reledit for instance).

A nice way of writing the hook is to use Python's sets to avoid
tedious logic code:

classRadioButtonUpdateHook(Hook):'''ensure use_option1 = not use_option2 (and conversely)'''__regid__='mycube.radiobuttonhook'events=('before_update_entity','before_add_entity')__select__=Hook.__select__&is_instance('MyEntity')# we prebuild the set of boolean attribute names_flag_attributes=set(('use_option1','use_option2'))def__call__(self):entity=self.entityedited=set(entity.cw_edited)attributes=self._flag_attributesifattributes.issubset(edited):# both were changed, let the integrity hooks do their jobreturnifnotattributes&edited:# none of our attributes where changed, do nothingreturn# find which attribute was modifiedmodified_set=attributes&edited# find the name of the other attributeto_change=(attributes-modified_set).pop()modified_name=modified_set.pop()# set the value of that attributeentity.cw_edited[to_change]=notentity.cw_edited[modified_name]