-
-
Notifications
You must be signed in to change notification settings - Fork 12
Initial Release - foreach API #1
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
languages: | ||
JavaScript: false | ||
Python: true |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
[run] | ||
|
||
branch = True | ||
|
||
[report] | ||
|
||
exclude_lines = | ||
pragma: no cover | ||
def __repr__ | ||
if self.debug: | ||
raise NotImplementedError | ||
if __name__ == .__main__.: | ||
|
||
ignore_errors = True | ||
|
||
include = | ||
*/oca/* | ||
|
||
omit = | ||
*/virtualenv/* | ||
*/tests/* | ||
setup.py | ||
*/__init__.py | ||
tests.py | ||
|
||
[xml] | ||
|
||
output = coverage.xml |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
# C extensions | ||
*.so | ||
|
||
# Distribution / packaging | ||
.Python | ||
env/ | ||
build/ | ||
develop-eggs/ | ||
dist/ | ||
downloads/ | ||
eggs/ | ||
.eggs/ | ||
lib/ | ||
lib64/ | ||
parts/ | ||
sdist/ | ||
var/ | ||
*.egg-info/ | ||
.installed.cfg | ||
*.egg | ||
|
||
# PyInstaller | ||
# Usually these files are written by a python script from a template | ||
# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
*.manifest | ||
*.spec | ||
|
||
# Installer logs | ||
pip-log.txt | ||
pip-delete-this-directory.txt | ||
|
||
# Unit test / coverage reports | ||
htmlcov/ | ||
.tox/ | ||
.coverage | ||
.coverage.* | ||
.cache | ||
nosetests.xml | ||
coverage.xml | ||
*,cover | ||
.hypothesis/ | ||
|
||
# Translations | ||
*.mo | ||
*.pot | ||
|
||
# Django stuff: | ||
*.log | ||
local_settings.py | ||
|
||
# Flask stuff: | ||
instance/ | ||
.webassets-cache | ||
|
||
# Scrapy stuff: | ||
.scrapy | ||
|
||
# Sphinx documentation | ||
docs/_build/ | ||
|
||
# PyBuilder | ||
target/ | ||
|
||
# IPython Notebook | ||
.ipynb_checkpoints | ||
|
||
# pyenv | ||
.python-version | ||
|
||
# celery beat schedule file | ||
celerybeat-schedule | ||
|
||
# dotenv | ||
.env | ||
|
||
# virtualenv | ||
venv/ | ||
ENV/ | ||
|
||
# Spyder project settings | ||
.spyderproject | ||
|
||
# Rope project settings | ||
.ropeproject | ||
|
||
# PyCharm | ||
.idea/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
cache: pip | ||
|
||
language: python | ||
|
||
python: | ||
- "2.7" | ||
- "3.5" | ||
- "3.6" | ||
|
||
install: | ||
- pip install tox-travis | ||
- pip install codecov | ||
- pip install codeclimate-test-reporter | ||
|
||
script: | ||
- tox | ||
|
||
after_success: | ||
- codecov | ||
- codeclimate-test-reporter | ||
|
||
deploy: | ||
provider: pypi | ||
user: laslabs | ||
password: | ||
secure: "UOFAfNJj1NNP3qI73IzrTncleyxSHwnYVpRe5vgAzlg0ojZWFTPRzac9JxKOvZPViuPnS+v8/UOequEz7sEOwLnYQIZcW1k4TAYWSNeAhjn7MpcboaSsujgGE1eMYWor3pgnU6f0EvBp0bhgfxciwHhjfU6PSr2CAfmJDjT02G1lsk8N94gTSYNwy+FV3QRPWlsB+ZyGGoUwf+Ap0gh7U3EaFSeVZ8P+y8oP99A1Zyz4dd0GjW2/5zj4eXm6boDUGt8sPAATf0Lni3xMfE/T+43MfMYRj1Yw6Ho7+mgYLL+RpgrY7pHA3pfOTomoz11yHnNYZq3sCKjDclspq64XSryICGOYC9hDT5vz+GbFzbpcnimbitdhO8STLPK9O0AMbrbanPaHVtNpC7dA+ZKpXtkD2UYN/GUVcc//nDCkGs6T1bFHFV9NUKfEqLr6LpS6Yb9MLc0g+x3b1+632FfoZ5+8uxM+NKHgh6uos9DPiLx8ZOCfgqVUqXexJq21bFuELqMkHZEu01Pe2MIB5K5ol3KDETYTYJJq4XF6+kF4Ge64LV+iRCP9WVxnX8OtovYxE5/56lB9S7Qc57Y1PpVupUGCo67wVE0UP7LHcs7qfEKmS/ulr2ARYNBVO0vfWrWm+9EnP/HNwqok4cna2/voVgoXNFeAj4u8+v2TfvKfIGg=" | ||
distributions: "sdist bdist_wheel" | ||
skip_upload_docs: true | ||
on: | ||
repo: oca/oca-decorators | ||
branch: master | ||
tags: true | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
|License LGPL-3| | |PyPi Package| | |PyPi Versions| | ||
|
||
|Build Status| | |Test Coverage| | |Code Climate| | ||
|
||
========== | ||
Python OCA | ||
========== | ||
|
||
This library contains helpers for Odoo developers, such as: | ||
|
||
* ``oca.decorators.foreach`` - A replacement for the deprecated ``odoo.api.one`` | ||
|
||
Installation | ||
============ | ||
|
||
Install this package into your Odoo environment. | ||
|
||
Using Pip: | ||
|
||
pip install oca-decorators | ||
|
||
Using Git: | ||
|
||
git clone https://github.com/OCA/oca-decorators | ||
python oca-decorators/setup.py install | ||
|
||
|
||
Setup | ||
===== | ||
|
||
Usage | ||
===== | ||
|
||
* `Read The API Documentation <https://oca.github.io/oca-decorators>`_ | ||
|
||
Known Issues / Road Map | ||
======================= | ||
|
||
|
||
Credits | ||
======= | ||
|
||
Images | ||
------ | ||
|
||
Contributors | ||
------------ | ||
|
||
* Dave Lasley <dave@laslabs.com> | ||
|
||
Maintainer | ||
---------- | ||
|
||
.. image:: https://odoo-community.org/logo.png | ||
:alt: Odoo Community Association | ||
:target: https://odoo-community.org | ||
|
||
This library 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. | ||
|
||
.. |Build Status| image:: https://img.shields.io/travis/OCA/oca-decorators/master.svg | ||
:target: https://travis-ci.org/OCA/oca-decorators | ||
.. |Test Coverage| image:: https://img.shields.io/codecov/c/github/OCA/oca-decorators/master.svg | ||
:target: https://codecov.io/gh/OCA/oca-decorators | ||
.. |Code Climate| image:: https://img.shields.io/codeclimate/github/OCA/oca-decorators.svg | ||
:target: https://codeclimate.com/github/OCA/oca-decorators | ||
.. |License LGPL-3| image:: https://img.shields.io/github/license/OCA/oca-decorators.svg | ||
:target: http://www.gnu.org/licenses/lgpl | ||
:alt: License: LGPL-3 | ||
.. |PyPi Package| image:: https://img.shields.io/pypi/v/oca-decorators.svg | ||
:target: https://pypi.python.org/pypi/oca-decorators | ||
:alt: PyPi Package | ||
.. |PyPi Versions| image:: https://img.shields.io/pypi/pyversions/oca-decorators.svg | ||
:target: https://pypi.python.org/pypi/oca-decorators | ||
:alt: PyPi Versions |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2016 LasLabs Inc. | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
|
||
__path__ = __import__('pkgutil').extend_path(__path__, __name__) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2016 LasLabs Inc. | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
|
||
from .foreach import foreach | ||
|
||
|
||
__all__ = [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @lasley You can leave this file empty. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is required in order to make the Otherwise usage is:
instead of
Do you have a better way to solve this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we really want one file per decorator? 😲 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I generally prefer deeper file hierarchies with smaller files. I've found that if I don't do this type of thing from the get-go I end up in a situation where the files are thousands of lines deep, I spend a bunch of time trying to categorize things, then just lose stuff anyways. I'm open to consideration here though. You would prefer to categorize/group somehow? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @lasley IMO Your way of organizing your code is safe. |
||
'foreach', | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2004-2015 Odoo S.A. | ||
# Copyright 2016-2017 LasLabs Inc. | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
|
||
from decorator import decorator | ||
|
||
|
||
def foreach(container=None): | ||
""" Loop the decorated method and return the results in a new `container`. | ||
|
||
Example: | ||
|
||
.. code-block:: python | ||
|
||
@helpers.foreach(list) | ||
def method(self): | ||
return self.id | ||
|
||
If the above method is called on a Record Singleton with the ``id`` 1 | ||
it would return: | ||
|
||
[1] | ||
|
||
If the method is called on a RecordSet containing Records with ``id`` | ||
1, 2, and 3 it would return: | ||
|
||
[1, 2, 3] | ||
|
||
If no container is provided as an argument to the decorator, and a | ||
value is returned from the decorated method, a ValueError will be | ||
raised. | ||
|
||
.. code-block:: python | ||
|
||
@helpers.foreach() | ||
def method(self): | ||
# Raises ValueError | ||
return 1+2 | ||
|
||
@helpers.foreach() | ||
def method(self): | ||
# No error raised | ||
self.math = 1+2 | ||
|
||
Args: | ||
container (callable): It will be called with an iterable of the | ||
decorated method results, then returned. | ||
|
||
Raises: | ||
AssertionError: If no container type is provided, and a value is | ||
returned from the decorated method. This will only be raised if | ||
``PYTHONOPTIMIZE`` is less than 2. | ||
TypeError: If an incorrect data type is provided as `container`. | ||
Valid arguments are `None` or any callable. | ||
|
||
Returns: | ||
mixed: A new `container`, instantiated with the results of the | ||
decorated method - iterated so that `self` is a singleton. | ||
""" | ||
|
||
def _foreach(method): | ||
|
||
def loop(method, self, *args, **kwargs): | ||
results = (method(rec, *args, **kwargs) for rec in self) | ||
if container is None: | ||
for result in results: | ||
assert result is None | ||
else: | ||
return container(results) | ||
|
||
wrapper = decorator(loop, method) | ||
wrapper._helpers = 'foreach' | ||
return wrapper | ||
|
||
return _foreach |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2016 LasLabs Inc. | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2016-2017 LasLabs Inc. | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
|
||
|
||
class TestRecordset(object): | ||
""" It provides a mock RecordSet for testing """ | ||
|
||
records = ['test1', 'test2'] | ||
iter_count = 0 | ||
|
||
def __iter__(self): | ||
for record in self.records: | ||
yield record | ||
self.iter_count += 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lasley This file must only contain
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
to keep oca as a reusable namespace package.https://packaging.python.org/guides/packaging-namespace-packages/#pkgutil-style-namespace-packages
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the complexity of having the package split doesn't pay. It's just easier to have all in one place, this shouldn't grow up so much as to be unmaintainable. Just a collection of helpers...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yajo I think we must keep the possibility to release others python packages under the oca namespace. (ie: utilities to use in our dev/release process, ????). There is nothing complex here.