diff --git a/api_foreach/README.rst b/api_foreach/README.rst new file mode 100644 index 00000000000..4e16cee4e0b --- /dev/null +++ b/api_foreach/README.rst @@ -0,0 +1,52 @@ +.. image:: https://img.shields.io/badge/license-LGPL--3-blue.svg + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 + +=========== +API Foreach +=========== + +This module provides an api decorator that iterates a Recordset and returns a +list of the results. This decorator is identical to the operation of the deprecated +``api.one``. + +Known Issues / Roadmap +====================== + + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us to smash it by providing detailed and welcomed feedback. + + +Credits +======= + +Images +------ + +* Odoo Community Association: `Icon `_. + +Contributors +------------ + +* Dave Lasley + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/api_foreach/__init__.py b/api_foreach/__init__.py new file mode 100644 index 00000000000..af97f4d4852 --- /dev/null +++ b/api_foreach/__init__.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 LasLabs Inc. +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +import odoo + +from .api import foreach + + +def _patch_api(*arg, **kwargs): + odoo.api.foreach = foreach + odoo.api.__all__.append('foreach') diff --git a/api_foreach/__manifest__.py b/api_foreach/__manifest__.py new file mode 100644 index 00000000000..80eb3753250 --- /dev/null +++ b/api_foreach/__manifest__.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 LasLabs Inc. +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). +{ + + 'name': 'API Foreach', + "summary": "It provides an API decorator that auto iterates recordsets.", + 'version': '10.0.1.0.0', + 'author': "LasLabs, Odoo Community Association (OCA)", + 'category': 'Base', + 'depends': [ + 'base', + ], + "website": "https://laslabs.com", + "license": "LGPL-3", + 'post_load': '_patch_api', + 'installable': True, +} diff --git a/api_foreach/api.py b/api_foreach/api.py new file mode 100644 index 00000000000..230eaef5ef4 --- /dev/null +++ b/api_foreach/api.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Copyright 2004-2015 Odoo S.A. +# Copyright 2016 LasLabs Inc. +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from odoo.api import aggregate, decorator + + +def foreach(method): + """ Decorate a record-style method where ``self`` is expected to be a + singleton instance. The decorated method automatically loops on + records, and makes a list with the results. In case the method is + decorated with :func:`returns`, it concatenates the resulting + instances. Such as + method:: + @api.foreach + def method(self, args): + return self.name + may be called in both record and traditional styles, like:: + # recs = model.browse(cr, uid, ids, context) + names = recs.method(args) + names = model.method(cr, uid, ids, args, context=context) + """ + def loop(method, self, *args, **kwargs): + result = [method(rec, *args, **kwargs) for rec in self] + return aggregate(method, result, self) + + wrapper = decorator(loop, method) + wrapper._api = 'foreach' + return wrapper diff --git a/api_foreach/tests/__init__.py b/api_foreach/tests/__init__.py new file mode 100644 index 00000000000..2d139d471df --- /dev/null +++ b/api_foreach/tests/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 LasLabs Inc. +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from . import test_api_foreach diff --git a/api_foreach/tests/test_api_foreach.py b/api_foreach/tests/test_api_foreach.py new file mode 100644 index 00000000000..4a5c0facb65 --- /dev/null +++ b/api_foreach/tests/test_api_foreach.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 LasLabs Inc. +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from odoo import api +from odoo.tests.common import TransactionCase + + +class TestRecordset(object): + """ It provides a mock recordset for testing foreach api """ + + records = ['test1', 'test2'] + + def __iter__(self): + for record in self.records: + yield record + + @api.foreach + def decorated_method(self): + """ It provides a method decorated with foreach """ + return self + + +class TestApiForeach(TransactionCase): + + def setUp(self): + super(TestApiForeach, self).setUp() + self.count = 0 + + def test_api_monkey_patch(self): + """ It should monkey-patch api.foreach into odoo.api """ + self.assertTrue( + callable(api.foreach), + ) + + def test_api_iterate(self): + """ It should iterate and return list of method results """ + res = TestRecordset().decorated_method() + self.assertEqual( + res, TestRecordset.records, + ) + + def test_api_foreach_append_all(self): + """ It should add ``foreach`` to ``__all__`` of ``odoo.api`` """ + self.assertIn('foreach', api.__all__)