[FIX] api: improve decorator `returns` to handle special cases, like method `search`
Add the possibility in the decorator to specify the `upgrade` and `downgrade` functions that convert values between APIs. Both function have the same API: upgrade(self, value, *args, **kwargs) downgrade(self, value, *args, **kwargs) The arguments ``self``, ``*args`` and ``**kwargs`` are the ones passed to the method, following its new-API signature. Fixes #4944, #7830.
This commit is contained in:
parent
3e03cfe7ac
commit
8e1a5add38
|
@ -66,6 +66,15 @@ class TestAPI(common.TransactionCase):
|
|||
self.assertIsRecordset(partners2, 'res.partner')
|
||||
self.assertEqual(list(partners1), list(partners2))
|
||||
|
||||
@mute_logger('openerp.models')
|
||||
def test_04_query_count(self):
|
||||
""" Test the search method with count=True. """
|
||||
count1 = self.registry('res.partner').search(self.cr, self.uid, [], count=True)
|
||||
count2 = self.env['res.partner'].search([], count=True)
|
||||
self.assertIsInstance(count1, (int, long))
|
||||
self.assertIsInstance(count2, (int, long))
|
||||
self.assertEqual(count1, count2)
|
||||
|
||||
@mute_logger('openerp.models')
|
||||
def test_05_immutable(self):
|
||||
""" Check that a recordset remains the same, even after updates. """
|
||||
|
|
|
@ -209,13 +209,19 @@ def depends(*args):
|
|||
return lambda method: decorate(method, '_depends', args)
|
||||
|
||||
|
||||
def returns(model, downgrade=None):
|
||||
def returns(model, downgrade=None, upgrade=None):
|
||||
""" Return a decorator for methods that return instances of ``model``.
|
||||
|
||||
:param model: a model name, or ``'self'`` for the current model
|
||||
|
||||
:param downgrade: a function ``downgrade(value)`` to convert the
|
||||
record-style ``value`` to a traditional-style output
|
||||
:param downgrade: a function ``downgrade(self, value, *args, **kwargs)``
|
||||
to convert the record-style ``value`` to a traditional-style output
|
||||
|
||||
:param upgrade: a function ``upgrade(self, value, *args, **kwargs)``
|
||||
to convert the traditional-style ``value`` to a record-style output
|
||||
|
||||
The arguments ``self``, ``*args`` and ``**kwargs`` are the ones passed
|
||||
to the method in the record-style.
|
||||
|
||||
The decorator adapts the method output to the api style: ``id``, ``ids`` or
|
||||
``False`` for the traditional style, and recordset for the record style::
|
||||
|
@ -237,7 +243,7 @@ def returns(model, downgrade=None):
|
|||
a decorated existing method will be decorated with the same
|
||||
``@returns(model)``.
|
||||
"""
|
||||
return lambda method: decorate(method, '_returns', (model, downgrade))
|
||||
return lambda method: decorate(method, '_returns', (model, downgrade, upgrade))
|
||||
|
||||
|
||||
def make_wrapper(decorator, method, old_api, new_api):
|
||||
|
@ -260,30 +266,39 @@ def make_wrapper(decorator, method, old_api, new_api):
|
|||
|
||||
|
||||
def get_downgrade(method):
|
||||
""" Return a function `downgrade(value)` that adapts ``value`` from
|
||||
record-style to traditional-style, following the convention of ``method``.
|
||||
""" Return a function `downgrade(self, value, *args, **kwargs)` that adapts
|
||||
``value`` from record-style to traditional-style, following the
|
||||
convention of ``method``.
|
||||
"""
|
||||
spec = getattr(method, '_returns', None)
|
||||
if spec:
|
||||
model, downgrade = spec
|
||||
return downgrade or (lambda value: value.ids)
|
||||
_, downgrade, _ = spec
|
||||
if downgrade and len(getargspec(downgrade).args) > 1:
|
||||
return downgrade
|
||||
elif downgrade:
|
||||
return lambda self, *args, **kwargs: downgrade(args[0])
|
||||
else:
|
||||
return lambda self, *args, **kwargs: args[0].ids
|
||||
else:
|
||||
return lambda value: value
|
||||
return lambda self, *args, **kwargs: args[0]
|
||||
|
||||
|
||||
def get_upgrade(method):
|
||||
""" Return a function `upgrade(self, value)` that adapts ``value`` from
|
||||
traditional-style to record-style, following the convention of ``method``.
|
||||
""" Return a function `upgrade(self, value, *args, **kwargs)` that adapts
|
||||
``value`` from traditional-style to record-style, following the
|
||||
convention of ``method``.
|
||||
"""
|
||||
spec = getattr(method, '_returns', None)
|
||||
if spec:
|
||||
model, downgrade = spec
|
||||
if model == 'self':
|
||||
return lambda self, value: self.browse(value)
|
||||
model, _, upgrade = spec
|
||||
if upgrade:
|
||||
return upgrade
|
||||
elif model == 'self':
|
||||
return lambda self, *args, **kwargs: self.browse(args[0])
|
||||
else:
|
||||
return lambda self, value: self.env[model].browse(value)
|
||||
return lambda self, *args, **kwargs: self.env[model].browse(args[0])
|
||||
else:
|
||||
return lambda self, value: value
|
||||
return lambda self, *args, **kwargs: args[0]
|
||||
|
||||
|
||||
def get_aggregate(method):
|
||||
|
@ -293,7 +308,7 @@ def get_aggregate(method):
|
|||
spec = getattr(method, '_returns', None)
|
||||
if spec:
|
||||
# value is a list of instances, concatenate them
|
||||
model, downgrade = spec
|
||||
model, _, _ = spec
|
||||
if model == 'self':
|
||||
return lambda self, value: sum(value, self.browse())
|
||||
else:
|
||||
|
@ -343,7 +358,7 @@ def model(method):
|
|||
context, args, kwargs = split(args, kwargs)
|
||||
recs = self.browse(cr, uid, [], context)
|
||||
result = method(recs, *args, **kwargs)
|
||||
return downgrade(result)
|
||||
return downgrade(recs, result, *args, **kwargs)
|
||||
|
||||
return make_wrapper(model, method, old_api, method)
|
||||
|
||||
|
@ -370,7 +385,7 @@ def multi(method):
|
|||
context, args, kwargs = split(args, kwargs)
|
||||
recs = self.browse(cr, uid, ids, context)
|
||||
result = method(recs, *args, **kwargs)
|
||||
return downgrade(result)
|
||||
return downgrade(recs, result, *args, **kwargs)
|
||||
|
||||
return make_wrapper(multi, method, old_api, method)
|
||||
|
||||
|
@ -410,7 +425,7 @@ def one(method):
|
|||
context, args, kwargs = split(args, kwargs)
|
||||
recs = self.browse(cr, uid, ids, context)
|
||||
result = new_api(recs, *args, **kwargs)
|
||||
return downgrade(result)
|
||||
return downgrade(recs, result, *args, **kwargs)
|
||||
|
||||
def new_api(self, *args, **kwargs):
|
||||
result = [method(rec, *args, **kwargs) for rec in self]
|
||||
|
@ -433,7 +448,7 @@ def cr(method):
|
|||
def new_api(self, *args, **kwargs):
|
||||
cr, uid, context = self.env.args
|
||||
result = method(self._model, cr, *args, **kwargs)
|
||||
return upgrade(self, result)
|
||||
return upgrade(self, result, *args, **kwargs)
|
||||
|
||||
return make_wrapper(cr, method, method, new_api)
|
||||
|
||||
|
@ -444,9 +459,9 @@ def cr_context(method):
|
|||
|
||||
def new_api(self, *args, **kwargs):
|
||||
cr, uid, context = self.env.args
|
||||
kwargs['context'] = context
|
||||
result = method(self._model, cr, *args, **kwargs)
|
||||
return upgrade(self, result)
|
||||
old_kwargs = dict(kwargs, context=context)
|
||||
result = method(self._model, cr, *args, **old_kwargs)
|
||||
return upgrade(self, result, *args, **kwargs)
|
||||
|
||||
return make_wrapper(cr_context, method, method, new_api)
|
||||
|
||||
|
@ -458,7 +473,7 @@ def cr_uid(method):
|
|||
def new_api(self, *args, **kwargs):
|
||||
cr, uid, context = self.env.args
|
||||
result = method(self._model, cr, uid, *args, **kwargs)
|
||||
return upgrade(self, result)
|
||||
return upgrade(self, result, *args, **kwargs)
|
||||
|
||||
return make_wrapper(cr_uid, method, method, new_api)
|
||||
|
||||
|
@ -477,9 +492,9 @@ def cr_uid_context(method):
|
|||
|
||||
def new_api(self, *args, **kwargs):
|
||||
cr, uid, context = self.env.args
|
||||
kwargs['context'] = context
|
||||
result = method(self._model, cr, uid, *args, **kwargs)
|
||||
return upgrade(self, result)
|
||||
old_kwargs = dict(kwargs, context=context)
|
||||
result = method(self._model, cr, uid, *args, **old_kwargs)
|
||||
return upgrade(self, result, *args, **kwargs)
|
||||
|
||||
return make_wrapper(cr_uid_context, method, method, new_api)
|
||||
|
||||
|
@ -494,7 +509,7 @@ def cr_uid_id(method):
|
|||
def new_api(self, *args, **kwargs):
|
||||
cr, uid, context = self.env.args
|
||||
result = [method(self._model, cr, uid, id, *args, **kwargs) for id in self.ids]
|
||||
return upgrade(self, result)
|
||||
return upgrade(self, result, *args, **kwargs)
|
||||
|
||||
return make_wrapper(cr_uid_id, method, method, new_api)
|
||||
|
||||
|
@ -518,9 +533,9 @@ def cr_uid_id_context(method):
|
|||
|
||||
def new_api(self, *args, **kwargs):
|
||||
cr, uid, context = self.env.args
|
||||
kwargs['context'] = context
|
||||
result = [method(self._model, cr, uid, id, *args, **kwargs) for id in self.ids]
|
||||
return upgrade(self, result)
|
||||
old_kwargs = dict(kwargs, context=context)
|
||||
result = [method(self._model, cr, uid, id, *args, **old_kwargs) for id in self.ids]
|
||||
return upgrade(self, result, *args, **kwargs)
|
||||
|
||||
return make_wrapper(cr_uid_id_context, method, method, new_api)
|
||||
|
||||
|
@ -535,7 +550,7 @@ def cr_uid_ids(method):
|
|||
def new_api(self, *args, **kwargs):
|
||||
cr, uid, context = self.env.args
|
||||
result = method(self._model, cr, uid, self.ids, *args, **kwargs)
|
||||
return upgrade(self, result)
|
||||
return upgrade(self, result, *args, **kwargs)
|
||||
|
||||
return make_wrapper(cr_uid_ids, method, method, new_api)
|
||||
|
||||
|
@ -561,9 +576,9 @@ def cr_uid_ids_context(method):
|
|||
|
||||
def new_api(self, *args, **kwargs):
|
||||
cr, uid, context = self.env.args
|
||||
kwargs['context'] = context
|
||||
result = method(self._model, cr, uid, self.ids, *args, **kwargs)
|
||||
return upgrade(self, result)
|
||||
old_kwargs = dict(kwargs, context=context)
|
||||
result = method(self._model, cr, uid, self.ids, *args, **old_kwargs)
|
||||
return upgrade(self, result, *args, **kwargs)
|
||||
|
||||
return make_wrapper(cr_uid_ids_context, method, method, new_api)
|
||||
|
||||
|
|
|
@ -1625,7 +1625,9 @@ class BaseModel(object):
|
|||
return len(res)
|
||||
return res
|
||||
|
||||
@api.returns('self')
|
||||
@api.returns('self',
|
||||
upgrade=lambda self, value, args, offset=0, limit=None, order=None, count=False: value if count else self.browse(value),
|
||||
downgrade=lambda self, value, args, offset=0, limit=None, order=None, count=False: value if count else value.ids)
|
||||
def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
|
||||
""" search(args[, offset=0][, limit=None][, order=None][, count=False])
|
||||
|
||||
|
|
Loading…
Reference in New Issue