How to extend fields.selection options without overwriting them?

Following an old discussion on openerp-expert-framework mailing list, it seems there is still no official way to extend the options of a selection field, without overwriting them.

The use case is the following:

Both module A and module B extend state field of sale.order with, respectively, stateA and stateB

Modules A and B don't know each other, so I want that if I install both of them, stateA and stateB are both added

When you don't have control on the original model

Say you want to modify the selection field type of the product categories. Excerpt of the code from the product addon, that you can't modify:

class product_category(osv.osv):
    # <snip>
    _name = "product.category"
    _description = "Product Category"
    _columns = {
    # <snip>
        'type': fields.selection([('view','View'), ('normal','Normal')], 'Category Type', help="A category of the view type is a virtual category that can be used as the parent of another category to create a hierarchical structure."),
    }

In your module you need to alter the field in the _columns in the __init__ of the model:

class product_category(orm.Model):
    _inherit = 'product.category'

    def __init__(self, cr, uid, name, context=None):
        super(product_category, self).__init__(cr, uid, name, context)
        option = ('special', 'Special')
        type_selection = self._columns['type'].selection
        if option not in type_selection:
            type_selection.append(option)

When you have control on the original model

When the original model is declared in an addon that you own, you can open the selection for extension using a method:

class my_model(orm.Model):
    _name = 'my.model'

    def _type_selection(self, cr, uid, context=None):
        return [('view', 'View'), ('normal', 'Normal')]

    _columns = {
        'type': fields.selection(_type_selection, string='Type'),
    }

As a result you are now able to extend the selection in other modules as follows:

class my_model(orm.Model):
    _inherit = 'my.model'

    def _type_selection(self, cr, uid, context=None):
        selection = super(my_model, self)._type_selection(cr, uid, context=context)
        selection.append(('special', 'Special'))
        return selection

Need more info?

This documentation page has been extracted from the Q&A section where you can discuss it and get feedback.
Related question