[Python-modules-commits] [python-odoorpc] 02/06: Import python-odoorpc_0.5.1.orig.tar.gz

Wolfgang Borgert debacle at moszumanska.debian.org
Sun Jan 22 13:40:19 UTC 2017


This is an automated email from the git hooks/post-receive script.

debacle pushed a commit to branch master
in repository python-odoorpc.

commit 30a2f6f1f9bab0404ebcb9347711f70b56afa68e
Author: W. Martin Borgert <debacle at debian.org>
Date:   Sun Jan 22 13:26:15 2017 +0000

    Import python-odoorpc_0.5.1.orig.tar.gz
---
 .travis.yml                           | 13 ++++++----
 CHANGELOG                             | 21 +++++++++++++++
 README.rst                            |  4 +--
 doc/source/conf.py                    |  5 ++--
 doc/source/download_install.rst       |  2 +-
 doc/source/faq.rst                    | 12 ++++-----
 doc/source/index.rst                  |  6 ++---
 doc/source/tuto_browse.rst            |  4 +--
 doc/source/tuto_browse_methods.rst    |  2 +-
 doc/source/tuto_browse_update.rst     | 47 +++++++++++++++++----------------
 doc/source/tuto_login.rst             |  8 +++---
 doc/source/tuto_report.rst            | 10 +++----
 doc/source/tuto_rpc_queries.rst       |  4 +--
 doc/source/tuto_session.rst           |  2 +-
 doc/source/tutorials.rst              |  5 ++++
 odoorpc/__init__.py                   |  2 +-
 odoorpc/error.py                      | 15 ++++++++---
 odoorpc/models.py                     |  4 +++
 odoorpc/odoo.py                       | 13 +++++-----
 odoorpc/rpc/__init__.py               | 49 +++++++++++++++++++++++++----------
 odoorpc/session.py                    |  4 +--
 odoorpc/tests/__init__.py             | 16 ++++++++----
 odoorpc/tests/test_db.py              |  1 +
 odoorpc/tests/test_field_binary.py    | 38 +++++++++++++++++++++++++++
 odoorpc/tests/test_field_many2many.py | 47 ++++++++++++++++++---------------
 odoorpc/tests/test_field_reference.py | 44 +++++++++++++++++++++----------
 odoorpc/tests/test_init.py            | 10 +++++++
 setup.py                              |  2 +-
 28 files changed, 265 insertions(+), 125 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 4880f3e..0a033a6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,5 @@
 language: python
+cache: pip
 python:
   - "2.7"
   - "3.2"
@@ -8,23 +9,25 @@ python:
   - "pypy"
 
 env:
-  - ODOO_BRANCH=8.0 ORPC_TEST_VERSION=$ODOO_BRANCH
-  - ODOO_BRANCH=9.0 ORPC_TEST_VERSION=$ODOO_BRANCH
+  - ODOO_BRANCH=8.0 ORPC_TEST_VERSION=$ODOO_BRANCH ODOO_CMD="/usr/bin/python2.7 /usr/local/bin/openerp-server -r $USER --addons-path=/opt/odoo/addons"
+  - ODOO_BRANCH=9.0 ORPC_TEST_VERSION=$ODOO_BRANCH ODOO_CMD="/usr/bin/python2.7 /usr/local/bin/openerp-server -r $USER --addons-path=/opt/odoo/addons"
+  - ODOO_BRANCH=10.0 ORPC_TEST_VERSION=$ODOO_BRANCH ODOO_CMD="/usr/bin/python2.7 /usr/local/bin/odoo -r $USER --addons-path=/opt/odoo/addons"
 
 before_install:
+  # Upgrade pip
+  - "sudo pip install pip --upgrade"
   # Install wkhtmltox
   - "wget http://download.gna.org/wkhtmltopdf/0.12/0.12.1/wkhtmltox-0.12.1_linux-precise-amd64.deb"
   - "sudo dpkg -i wkhtmltox-0.12.1_linux-precise-amd64.deb || true"
   - "sudo apt-get update && sudo apt-get install -f -y"
   # Install Odoo on the system (outside the virtualenv)
   - "sudo git clone --depth=1 -b $ODOO_BRANCH https://github.com/odoo/odoo.git /opt/odoo"
-  - "sudo apt-get install python-pip"
-  - "sudo /usr/bin/pip install -r /opt/odoo/requirements.txt"
+  - "sudo pip install -r /opt/odoo/requirements.txt"
   - "echo $PWD"
   - "cd /opt/odoo && sudo /usr/bin/python setup.py install"
   - "cd $TRAVIS_BUILD_DIR"
   # Start Odoo
-  - "nohup /usr/bin/python2.7 /usr/local/bin/openerp-server -r $USER --addons-path=/opt/odoo/addons &"
+  - "nohup $ODOO_CMD &"
 
 install:
   # OdooRPC dependencies
diff --git a/CHANGELOG b/CHANGELOG
index d59e609..19a558c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,24 @@
+0.5.1
+=====
+- FIX: Session file loading, read the `timeout` value as a float
+
+0.5.0
+=====
+- IMP: Support added for Odoo 10.0
+- IMP: Documentation updated to be in line with Odoo 10.0
+
+0.4.3
+=====
+- IMP: Documentation (minor fixes)
+
+0.4.2
+=====
+- IMP: Unit tests:
+    - autodetect server version
+    - tests added for binary fields
+- IMP: The timeout can be set to 'None' (infinite timeout)
+- FIX: Underscore prefixed methods are not forwarded to the server
+
 0.4.1
 =====
 - IMP: New feature, check if a model exists in the Odoo database (see the
diff --git a/README.rst b/README.rst
index 6e26a97..2cad005 100644
--- a/README.rst
+++ b/README.rst
@@ -73,7 +73,7 @@ See the documentation for more details and features.
 Supported Odoo server versions
 ------------------------------
 
-`OdooRPC` has been tested on `Odoo` 8.0 and 9.0.
+`OdooRPC` has been tested on `Odoo` 8.0, 9.0 and 10.0.
 It should work on next versions if `Odoo` keeps a stable API.
 
 Supported Python versions
@@ -92,7 +92,7 @@ Generate the documentation
 To generate the documentation, you have to install `Sphinx` documentation
 generator::
 
-    easy_install -U sphinx
+    pip install sphinx
 
 Then, you can use the ``build_doc`` option of the ``setup.py``::
 
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 1d347ff..2946843 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -14,6 +14,7 @@
 
 import sys
 import os
+from datetime import datetime
 
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
@@ -40,7 +41,7 @@ PORT = os.environ.get('ORPC_TEST_PORT', 8069)
 DB = os.environ.get('ORPC_TEST_DB', 'odoorpc_doctest')
 USER = os.environ.get('ORPC_TEST_USER', 'admin')
 PWD = os.environ.get('ORPC_TEST_PWD', 'admin')
-VERSION = os.environ.get('ORPC_TEST_VERSION', '8.0')
+VERSION = os.environ.get('ORPC_TEST_VERSION', '10.0')
 SUPER_PWD = os.environ.get('ORPC_TEST_SUPER_PWD', 'admin')
 import odoorpc
 odoo = odoorpc.ODOO(HOST, protocol=PROTOCOL, port=PORT, version=VERSION)
@@ -75,7 +76,7 @@ master_doc = 'index'
 
 # General information about the project.
 project = u'OdooRPC'
-copyright = u'2014, Sébastien Alix'
+copyright = u'2014-{0}, Sébastien Alix'.format(datetime.now().year)
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
diff --git a/doc/source/download_install.rst b/doc/source/download_install.rst
index 0561b8e..b4d4d05 100644
--- a/doc/source/download_install.rst
+++ b/doc/source/download_install.rst
@@ -45,7 +45,7 @@ available::
     $ export ORPC_TEST_DB=odoorpc_test
     $ export ORPC_TEST_USER=admin
     $ export ORPC_TEST_PWD=admin
-    $ export ORPC_TEST_VERSION=8.0
+    $ export ORPC_TEST_VERSION=10.0
     $ export ORPC_TEST_SUPER_PWD=admin
     $ python -m unittest discover -v
 
diff --git a/doc/source/faq.rst b/doc/source/faq.rst
index 2d440c1..2ea56a1 100644
--- a/doc/source/faq.rst
+++ b/doc/source/faq.rst
@@ -33,10 +33,10 @@ It was a tough decision, but several reasons motivated the `OdooRPC` project:
 **New server API**
   One goal of `OERPLib` was to give an API not too different from the server
   side API to reduce the learning gap between server-side development and
-  client-side with an `RPC` library. With the new 8.0 API which appears in
-  `Odoo` 8.0 this is another brake (the old API will be removed one day), so
-  the current API of `OERPLib` will not be consistent for the next years.
-  As such, `OdooRPC` mimics A LOT the new API 8.0 of Odoo, for more
+  client-side with an `RPC` library. With the new API which appears in
+  `Odoo` 8.0 this is another brake (the old API has even been removed
+  since Odoo 10.0), so the current API of `OERPLib` is not anymore consistent.
+  As such, `OdooRPC` mimics A LOT the new API of Odoo, for more
   consistency (see the :ref:`tutorials <tutorials>`).
 
 **New brand Odoo**
@@ -46,7 +46,7 @@ It was a tough decision, but several reasons motivated the `OdooRPC` project:
   confusing for newcomers in the `Odoo` world. So, `OdooRPC` speaks for
   itself.
 
-**Maintening cost, code cleanup**
+**Maintenance cost, code cleanup**
   `OpenERP` has evolved a lot since the version 5.0 (2009), making `OERPLib`
   hard to maintain (write tests for all versions before each `OERPLib` and
   `OpenERP` release is very time consuming). All the compatibility code for
@@ -126,7 +126,7 @@ for instance::
 
     for session in odoorpc.ODOO.list():
         odoo = odoorpc.ODOO.load(session)
-        if v(odoo.version) > v('8.0'):
+        if v(odoo.version) < v('10.0'):
             pass  # do some stuff
         else:
             pass  # do something else
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 4910266..c04bb86 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -10,7 +10,7 @@ Introduction
 ------------
 
 **OdooRPC** is a Python module providing an easy way to
-pilot your **Odoo** servers through `RPC`.
+pilot your `Odoo <https://www.odoo.com>`_ servers through `RPC`.
 
 Features supported:
     - access to all data model methods (even ``browse``) with an API similar
@@ -79,7 +79,7 @@ Contents
 Supported Odoo server versions
 ------------------------------
 
-`OdooRPC` has been tested on `Odoo` 8.0 and 9.0.
+`OdooRPC` has been tested on `Odoo` 8.0, 9.0 and 10.0.
 It should work on next versions if `Odoo` keeps a stable API.
 
 Supported Python versions
@@ -96,7 +96,7 @@ Bugs or suggestions
 -------------------
 
 Please, feel free to report bugs or suggestions in the `Bug Tracker
-<TODO>`_!
+<https://github.com/osiell/odoorpc/issues>`_!
 
 Make a donation
 ---------------
diff --git a/doc/source/tuto_browse.rst b/doc/source/tuto_browse.rst
index e649b8f..4e3d7f3 100644
--- a/doc/source/tuto_browse.rst
+++ b/doc/source/tuto_browse.rst
@@ -40,10 +40,8 @@ and ``datetime.datetime``::
 
     >>> Purchase = odoo.env['purchase.order']
     >>> order = Purchase.browse(1)
-    >>> order.minimum_planned_date
-    datetime.date(2014, 10, 8)
     >>> order.date_order
-    datetime.datetime(2014, 10, 7, 20, 54, 21)
+    datetime.datetime(2016, 11, 6, 11, 23, 10)
 
 A list of data types used by records fields are available :ref:`here <fields>`.
 
diff --git a/doc/source/tuto_browse_methods.rst b/doc/source/tuto_browse_methods.rst
index 0f79685..0ad1118 100644
--- a/doc/source/tuto_browse_methods.rst
+++ b/doc/source/tuto_browse_methods.rst
@@ -30,4 +30,4 @@ This is a behaviour `by design`: `OdooRPC` has no way to make the difference
 between a `class` or an `instance` method through RPC, this is why it differs
 from the `Odoo` API.
 
-:ref:`Next step: Update data through browsable records <tuto-update-browse-records>`
+:ref:`Next step: Update data through records <tuto-update-browse-records>`
diff --git a/doc/source/tuto_browse_update.rst b/doc/source/tuto_browse_update.rst
index 5ae32f4..c7e1720 100644
--- a/doc/source/tuto_browse_update.rst
+++ b/doc/source/tuto_browse_update.rst
@@ -1,29 +1,30 @@
 .. _tuto-update-browse-records:
 
-Update data through browsable records
-*************************************
+Update data through records
+***************************
 
 By default when updating values of a record, the change is automatically sent
 to the server.
 Let's update the name of a partner::
 
     >>> Partner = odoo.env['res.partner']
-    >>> partner = Partner.browse(1)
-    >>> partner.name = "MyCompany"
+    >>> partner_id = Partner.create({'name': "Contact Test"})
+    >>> partner = Partner.browse(partner_id)
+    >>> partner.name = "MyContact"
 
 This is equivalent to::
 
-    >>> Partner.write([partner.id], {'name': "MyCompany"})
+    >>> Partner.write([partner.id], {'name': "MyContact"})
 
 As one update is equivalent to one RPC query, if you need to update several
 fields for one record it is encouraged to use the `write` method as above ::
 
-    >>> partner.write({'name': "MyCompany", 'website': 'http://example.net'})    # one RPC query
+    >>> partner.write({'name': "MyContact", 'website': 'http://example.net'})    # one RPC query
 
 Or, deactivate the ``auto_commit`` option and commit the changes manually::
 
     >>> odoo.config['auto_commit'] = False
-    >>> partner.name = "MyCompany"
+    >>> partner.name = "MyContact"
     >>> partner.website = 'http://example.net'
     >>> partner.env.commit()    # one RPC by record modified
 
@@ -41,15 +42,15 @@ Same as above, except there is a check about the value assigned. For instance,
 the field ``type`` of the ``res.partner`` model accept values contains
 in ``['default', 'invoice', 'delivery', 'contact', 'other']``::
 
-    >>> partner.type = 'default' # Ok
-    >>> partner.type = 'foobar'  # Error!
+    >>> partner.type = 'delivery'   # Ok
+    >>> partner.type = 'foobar'     # Error!
     Traceback (most recent call last):
       File "<stdin>", line 1, in <module>
       File "odoorpc/service/model/fields.py", line 148, in __set__
         value = self.check_value(value)
       File "odoorpc/service/model/fields.py", line 160, in check_value
         field_name=self.name,
-    ValueError: The value 'foobar' supplied doesn't match with the possible values '['default', 'invoice', 'delivery', 'contact', 'other']' for the 'type' field
+    ValueError: The value 'foobar' supplied doesn't match with the possible values '['contact', 'invoice', 'delivery', 'other']' for the 'type' field
 
 Many2one
 ''''''''
@@ -57,7 +58,7 @@ Many2one
 You can also update a ``many2one`` field, with either an ID or a record::
 
     >>> partner.parent_id = 1                   # with an ID
-    >>> partner.parent_id = Partner.browse(1)   # with a browsable record
+    >>> partner.parent_id = Partner.browse(1)   # with a record object
 
 You can't put any ID or record, a check is made on the relationship
 to ensure data integrity::
@@ -78,8 +79,9 @@ One2many and Many2many
 ''''''''''''''''''''''
 
 ``one2many`` and ``many2many`` fields can be updated by providing
-a list of tuple as specified in the `OpenERP/Odoo` documentation, a list of
-records, a list of record IDs or an empty list or ``False``:
+a list of tuple as specified in the `Odoo` documentation
+(`link <https://github.com/odoo/odoo/blob/10.0/odoo/models.py#L3479>`_),
+a list of records, a list of record IDs, an empty list or ``False``:
 
 With a tuple (as documented), no magic here::
 
@@ -142,13 +144,13 @@ With a record only::
 Reference
 '''''''''
 
-To update a ``reference`` field, you have to use either a string or a browsable
-record as below::
+To update a ``reference`` field, you have to use either a string or a record
+object as below::
 
     >>> IrActionServer = odoo.env['ir.actions.server']
-    >>> action_server = IrActionServer.browse(7)
-    >>> action_server.ref_object = 'res.partner,1'  # with a string with the format '{relation},{id}'
-    >>> action_server.ref_object = Partner.browse(1)    # with a browsable record
+    >>> action_server = IrActionServer.browse(8)
+    >>> action_server.ref_object = 'res.partner,1'      # with a string with the format '{relation},{id}'
+    >>> action_server.ref_object = Partner.browse(1)    # with a record object
 
 A check is made on the relation name::
 
@@ -174,13 +176,12 @@ With ``datetime.date`` and ``datetime.datetime`` objects::
     >>> import datetime
     >>> Purchase = odoo.env['purchase.order']
     >>> order = Purchase.browse(1)
-    >>> order.date_order = datetime.date(2011, 9, 20)
-    >>> order.minimum_planned_date = datetime.datetime(2011, 9, 20, 12, 31, 24)
+    >>> order.date_order = datetime.datetime(2016, 11, 7, 11, 23, 10)
 
 With formated strings::
 
-    >>> order.date_order = "2011-09-20"                     # %Y-%m-%d
-    >>> order.minimum_planned_date = "2011-09-20 12:31:24"  # %Y-%m-%d %H:%M:%S
+    >>> order.date_order = "2016-11-07"             # %Y-%m-%d
+    >>> order.date_order = "2016-11-07 12:31:24"    # %Y-%m-%d %H:%M:%S
 
 As always, a wrong type will raise an exception::
 
@@ -191,6 +192,6 @@ As always, a wrong type will raise an exception::
         value = self.check_value(value)
       File "odoorpc/fields.py", line 203, in check_value
         self.pattern))
-    ValueError: Value not well formatted, expecting '%Y-%m-%d' format
+    ValueError: Value not well formatted, expecting '%Y-%m-%d %H:%M:%S' format
 
 :ref:`Next step: Download reports <tuto-download-report>`
diff --git a/doc/source/tuto_login.rst b/doc/source/tuto_login.rst
index 81dcb27..0e30bf1 100644
--- a/doc/source/tuto_login.rst
+++ b/doc/source/tuto_login.rst
@@ -10,10 +10,10 @@ account of your choice::
 
 .. note::
 
-    Underhood the login method create a cookie, and all requests thereafter
-    which need a user authentication are cookie-based.
+    Under the hood the login method creates a cookie, and all requests
+    thereafter which need a user authentication are cookie-based.
 
-Once logged, you can check some information through the
+Once logged in, you can check some information through the
 :class:`environment <odoorpc.ODOO.env>`::
 
     >>> odoo.env.db
@@ -27,7 +27,7 @@ Once logged, you can check some information through the
     >>> odoo.env.user.name              # name of the user
     'Administrator'
     >>> odoo.env.user.company_id.name   # the name of its company
-    'Your Company'
+    'YourCompany'
 
 From now, you can easily execute any kind of queries on your
 `Odoo` server (execute model methods, trigger workflow, download reports...).
diff --git a/doc/source/tuto_report.rst b/doc/source/tuto_report.rst
index 7cfebba..550dbe1 100644
--- a/doc/source/tuto_report.rst
+++ b/doc/source/tuto_report.rst
@@ -3,7 +3,7 @@
 Download reports
 ****************
 
-Another nice functionnality is the reports generation with the
+Another nice feature is the reports generation with the
 :attr:`report <odoorpc.ODOO.report>` property.
 The :func:`list <odoorpc.report.Report.list>` method allows you to list
 all reports available on your `Odoo` server (classified by models), while the
@@ -13,16 +13,16 @@ retrieve a report as a file (in PDF, HTML... depending of the report).
 To list available reports::
 
     >>> odoo.report.list()
-    {u'ir.module.module': [{u'name': u'Technical guide', u'report_type': u'pdf', u'report_name': u'ir.module.reference'}], u'ir.model': [{u'name': u'Model Overview', u'report_type': u'sxw', u'report_name': u'ir.model.overview'}], u'res.partner': [{u'name': u'Labels', u'report_type': u'pdf', u'report_name': u'res.partner'}], u'res.company': [{u'name': u'Preview Report', u'report_type': u'pdf', u'report_name': u'preview.report'}]}
+    {u'account.invoice': [{u'name': u'Duplicates', u'report_type': u'qweb-pdf', u'report_name': u'account.account_invoice_report_duplicate_main'}, {u'name': u'Invoices', u'report_type': u'qweb-pdf', u'report_name': u'account.report_invoice'}], u'res.partner': [{u'name': u'Aged Partner Balance', u'report_type': u'qweb-pdf', u'report_name': u'account.report_agedpartnerbalance'}, {u'name': u'Due Payments', u'report_type': u'qweb-pdf', u'report_name': u'account.report_overdue'}], ...}
 
 To download a report::
 
-    >>> report = odoo.report.download('preview.report', [1])
+    >>> report = odoo.report.download('account.report_invoice', [1])
 
 The method will return a file-like object, you will have to read its content
-in order to save it on your filesystem::
+in order to save it on your file-system::
 
-    >>> with open('company_preview_report.pdf', 'w') as report_file:
+    >>> with open('invoice.pdf', 'w') as report_file:
     ...     report_file.write(report.read())
     ...
 
diff --git a/doc/source/tuto_rpc_queries.rst b/doc/source/tuto_rpc_queries.rst
index fec7108..5ca7cbd 100644
--- a/doc/source/tuto_rpc_queries.rst
+++ b/doc/source/tuto_rpc_queries.rst
@@ -30,13 +30,13 @@ context automatically::
     {'lang': 'fr_FR', 'tz': False}
     >>> Product = odoo.env['product.product']
     >>> Product.name_get([3, 4])
-    [[3, '[PC1] PC Basic'], [4, '[PC2] Basic+ PC (assembl\xe9 sur commande)']]
+    [[3, '[SERV_COST] Audit externe''], [4, '[PROD_DEL] Commutateur, 24 ports']]
 
 To stop sending the user context, use the :attr:`odoorpc.ODOO.config` property::
 
     >>> odoo.config['auto_context'] = False
     >>> Product.name_get([3, 4])    # Without context, lang 'en_US' by default
-    [[3, '[PC1] Basic PC'], [4, '[PC2] Basic+ PC (assembly on order)']]
+    [[3, '[SERV_COST] External Audit'], [4, '[PROD_DEL] Switch, 24 ports']]
 
 .. note::
 
diff --git a/doc/source/tuto_session.rst b/doc/source/tuto_session.rst
index e584ed9..27718c1 100644
--- a/doc/source/tuto_session.rst
+++ b/doc/source/tuto_session.rst
@@ -5,7 +5,7 @@ Save your credentials (session)
 
 Once you are authenticated with your :class:`ODOO <odoorpc.ODOO>` instance, you
 can :func:`save <odoorpc.ODOO.save>` your credentials under a code name and use
-this one to quickly instanciate a new :class:`ODOO <odoorpc.ODOO>` class::
+this one to quickly instantiate a new :class:`ODOO <odoorpc.ODOO>` class::
 
     >>> import odoorpc
     >>> odoo = odoorpc.ODOO('localhost')
diff --git a/doc/source/tutorials.rst b/doc/source/tutorials.rst
index 35ca5e6..00ed11d 100644
--- a/doc/source/tutorials.rst
+++ b/doc/source/tutorials.rst
@@ -3,6 +3,11 @@
 Tutorials
 =========
 
+.. note::
+
+    The tutorial is based on `Odoo 10.0`, the examples must be adapted
+    following the version of `Odoo` you are using.
+
 .. toctree::
     :maxdepth: 2
 
diff --git a/odoorpc/__init__.py b/odoorpc/__init__.py
index 5ea79fc..f4af113 100644
--- a/odoorpc/__init__.py
+++ b/odoorpc/__init__.py
@@ -28,7 +28,7 @@ automated jobs that communicate with a `Odoo` server.
 __author__ = 'ABF Osiell - Sebastien Alix'
 __email__ = 'sebastien.alix at osiell.com'
 __licence__ = 'LGPL v3'
-__version__ = '0.4.1'
+__version__ = '0.5.1'
 
 __all__ = ['ODOO', 'error']
 
diff --git a/odoorpc/error.py b/odoorpc/error.py
index 9936979..d359d7f 100644
--- a/odoorpc/error.py
+++ b/odoorpc/error.py
@@ -43,11 +43,12 @@ class RPCError(Error):
         ...     pp(exc.info)
         ...
         {'code': 200,
-         'data': {'arguments': ["'res.users' object has no attribute 'wrong_method'"],
+         'data': {'arguments': ["type object 'res.users' has no attribute 'wrong_method'"],
                   'debug': 'Traceback (most recent call last):\\n  File ...',
+                  'exception_type': 'internal_error',
                   'message': "'res.users' object has no attribute 'wrong_method'",
                   'name': 'exceptions.AttributeError'}
-         'message': 'OpenERP Server Error'}
+         'message': 'Odoo Server Error'}
 
     .. doctest::
         :hide:
@@ -58,9 +59,15 @@ class RPCError(Error):
         ... except odoorpc.error.RPCError as exc:
         ...     exc.info['code'] == 200
         ...     'message' in exc.info
-        ...     exc.info['data']['arguments'] == ["'res.users' object has no attribute 'wrong_method'"]
+        ...     exc.info['data']['arguments'] in [
+        ...         ["'res.users' object has no attribute 'wrong_method'"],         # >= 8.0
+        ...         ["type object 'res.users' has no attribute 'wrong_method'"],    # >= 10.0
+        ...     ]
         ...     exc.info['data']['debug'].startswith('Traceback (most recent call last):\\n  File')
-        ...     exc.info['data']['message'] == "'res.users' object has no attribute 'wrong_method'"
+        ...     exc.info['data']['message'] in [
+        ...         "'res.users' object has no attribute 'wrong_method'",           # >= 8.0
+        ...         "type object 'res.users' has no attribute 'wrong_method'",      # >= 10.0
+        ...     ]
         ...     exc.info['data']['name'] == 'exceptions.AttributeError'
         ...
         True
diff --git a/odoorpc/models.py b/odoorpc/models.py
index 67a85f8..6e5a1b8 100644
--- a/odoorpc/models.py
+++ b/odoorpc/models.py
@@ -63,6 +63,8 @@ class MetaModel(type):
 
     def __getattr__(cls, method):
         """Provide a dynamic access to a RPC method."""
+        if method.startswith('_'):
+            return super(MetaModel, cls).__getattr__(method)
         def rpc_method(*args, **kwargs):
             """Return the result of the RPC request."""
             if cls._odoo.config['auto_context'] \
@@ -325,6 +327,8 @@ class Model(BaseModel):
             True
 
         """
+        if method.startswith('_'):
+            return super(Model, self).__getattr__(method)
         def rpc_method(*args, **kwargs):
             """Return the result of the RPC request."""
             args = tuple([self.ids]) + args
diff --git a/odoorpc/odoo.py b/odoorpc/odoo.py
index ffaca4f..93d017d 100644
--- a/odoorpc/odoo.py
+++ b/odoorpc/odoo.py
@@ -46,7 +46,7 @@ class ODOO(object):
     .. doctest::
         :options: +SKIP
 
-        >>> odoo = odoorpc.ODOO('localhost', version='8.0')
+        >>> odoo = odoorpc.ODOO('localhost', version='10.0')
 
     *Python 2:*
 
@@ -73,9 +73,10 @@ class ODOO(object):
         except ValueError:
             raise ValueError("The port must be an integer")
         try:
-            timeout = int(timeout)
+            if timeout is not None:
+                timeout = float(timeout)
         except ValueError:
-            raise ValueError("The timeout must be an integer")
+            raise ValueError("The timeout must be a float")
         self._host = host
         self._port = port
         self._protocol = protocol
@@ -152,7 +153,7 @@ class ODOO(object):
             :options: +SKIP
 
             >>> odoo.version
-            '8.0'
+            '10.0'
         """
         return self._connector.version
 
@@ -268,7 +269,7 @@ class ODOO(object):
         return data
 
     def http(self, url, data=None, headers=None):
-        """Low level method to execute raw HTPP queries.
+        """Low level method to execute raw HTTP queries.
 
         .. note::
 
@@ -281,7 +282,7 @@ class ODOO(object):
         URL parameters (with :func:`urllib.urlencode` function for simple
         parameters, or multipart/form-data structure to handle file upload).
 
-        E.g., the HTTP raw query to backup a database on `Odoo 8.0`:
+        E.g., the HTTP raw query to get the company logo on `Odoo 10.0`:
 
         .. doctest::
 
diff --git a/odoorpc/rpc/__init__.py b/odoorpc/rpc/__init__.py
index c328c89..da45c54 100644
--- a/odoorpc/rpc/__init__.py
+++ b/odoorpc/rpc/__init__.py
@@ -92,24 +92,47 @@ class ConnectorJSONRPC(Connector):
         :options: +SKIP
 
         >>> cnt.proxy_json.web.session.authenticate(db='db_name', login='admin', password='password')
-        {'jsonrpc': '2.0', 'id': 202516757,
-         'result': {'username': 'admin', 'user_context': {'lang': 'fr_FR', 'tz': 'Europe/Brussels', 'uid': 1},
-         'db': 'db_name', 'company_id': 1, 'uid': 1, 'session_id': '308816f081394a9c803613895b988540'}}
+        {'id': 51373612,
+         'jsonrpc': '2.0',
+         'result': {'company_id': 1,
+                    'currencies': {'1': {'digits': [69, 2],
+                                         'position': 'after',
+                                         'symbol': '\u20ac'},
+                                   '3': {'digits': [69, 2],
+                                         'position': 'before',
+                                         'symbol': '$'}},
+                    'db': 'db_name',
+                    'is_admin': True,
+                    'is_superuser': True,
+                    'name': 'Administrator',
+                    'partner_id': 3,
+                    'server_version': '10.0',
+                    'server_version_info': [10, 0, 0, 'final', 0, ''],
+                    'session_id': '6dd7a34f16c1c67b38bfec413cca4962d5c01d53',
+                    'uid': 1,
+                    'user_companies': False,
+                    'user_context': {'lang': 'en_US',
+                                     'tz': 'Europe/Brussels',
+                                     'uid': 1},
+                    'username': 'admin',
+                    'web.base.url': 'http://localhost:8069',
+                    'web_tours': []}}
 
     .. doctest::
         :hide:
         :options: +NORMALIZE_WHITESPACE
 
-        >>> from pprint import pprint as pp
-        >>> pp(cnt.proxy_json.web.session.authenticate(db=DB, login=USER, password=PWD))
-        {'id': ...,
-         'jsonrpc': '2.0',
-         'result': {'company_id': 1,
-                    'db': ...,
-                    'session_id': ...,
-                    'uid': 1,
-                    'user_context': ...,
-                    'username': 'admin'}}
+        >>> from odoorpc.tools import v
+        >>> data = cnt.proxy_json.web.session.authenticate(db=DB, login=USER, password=PWD)
+        >>> keys = ['company_id', 'db', 'session_id', 'uid', 'user_context', 'username']
+        >>> if v(VERSION) >= v('10.0'):
+        ...     keys.extend([
+        ...         'currencies', 'is_admin', 'is_superuser', 'name',
+        ...         'partner_id', 'server_version', 'server_version_info',
+        ...         'user_companies', 'web.base.url', 'web_tours',
+        ...     ])
+        >>> all([key in data['result'] for key in keys])
+        True
 
     Read data of a partner:
 
diff --git a/odoorpc/session.py b/odoorpc/session.py
index bc04da8..fe874e4 100644
--- a/odoorpc/session.py
+++ b/odoorpc/session.py
@@ -79,7 +79,7 @@ def get_all(rc_file='~/.odoorpcrc'):
             'host': conf.get(name, 'host'),
             'protocol': conf.get(name, 'protocol'),
             'port': conf.getint(name, 'port'),
-            'timeout': conf.getint(name, 'timeout'),
+            'timeout': conf.getfloat(name, 'timeout'),
             'user': conf.get(name, 'user'),
             'passwd': conf.get(name, 'passwd'),
             'database': conf.get(name, 'database'),
@@ -137,7 +137,7 @@ def get(name, rc_file='~/.odoorpcrc'):
         'host': conf.get(name, 'host'),
         'protocol': conf.get(name, 'protocol'),
         'port': conf.getint(name, 'port'),
-        'timeout': conf.getint(name, 'timeout'),
+        'timeout': conf.getfloat(name, 'timeout'),
         'user': conf.get(name, 'user'),
         'passwd': conf.get(name, 'passwd'),
         'database': conf.get(name, 'database'),
diff --git a/odoorpc/tests/__init__.py b/odoorpc/tests/__init__.py
index d7fd2b8..fe24a78 100644
--- a/odoorpc/tests/__init__.py
+++ b/odoorpc/tests/__init__.py
@@ -23,31 +23,37 @@ class BaseTestCase(unittest.TestCase):
             'db': os.environ.get('ORPC_TEST_DB', 'odoorpc_test'),
             'user': os.environ.get('ORPC_TEST_USER', 'admin'),
             'pwd': os.environ.get('ORPC_TEST_PWD', 'admin'),
-            'version': os.environ.get('ORPC_TEST_VERSION', '8.0'),
+            'version': os.environ.get('ORPC_TEST_VERSION', None),
             'super_pwd': os.environ.get('ORPC_TEST_SUPER_PWD', 'admin'),
         }
         self.odoo = odoorpc.ODOO(
             self.env['host'], protocol=self.env['protocol'],
             port=self.env['port'], version=self.env['version'])
         # Create the database
+        default_timeout = self.odoo.config['timeout']
         self.odoo.config['timeout'] = 600
         if self.env['db'] not in self.odoo.db.list():
             self.odoo.db.create(
                 self.env['super_pwd'], self.env['db'], True)
-        self.odoo.config['timeout'] = 120
+        self.odoo.config['timeout'] = default_timeout
 
 
 class LoginTestCase(BaseTestCase):
     """Instanciates an ``odoorpc.ODOO`` object and perform the user login."""
     def setUp(self):
         BaseTestCase.setUp(self)
+        default_timeout = self.odoo.config['timeout']
         self.odoo.login(self.env['db'], self.env['user'], self.env['pwd'])
-        # Install 'sale' and 'crm' modules
+        # Install 'sale' + 'crm_claim' on Odoo < 10.0,
+        # and 'sale' + 'subscription' on Odoo >= 10.0
         self.odoo.config['timeout'] = 600
         module_obj = self.odoo.env['ir.module.module']
-        module_ids = module_obj.search([('name', 'in', ['sale', 'crm_claim'])])
+        modules = ['sale', 'crm_claim']
+        if self.odoo.version == '10.0':
+            modules = ['sale', 'subscription']
+        module_ids = module_obj.search([('name', 'in', modules)])
         module_obj.button_immediate_install(module_ids)
-        self.odoo.config['timeout'] = 120
+        self.odoo.config['timeout'] = default_timeout
         # Get user record and model after the installation of modules
         # to get all available fields (avoiding test failures)
         self.user = self.odoo.env.user
diff --git a/odoorpc/tests/test_db.py b/odoorpc/tests/test_db.py
index b07bbf0..5bc4afc 100644
--- a/odoorpc/tests/test_db.py
+++ b/odoorpc/tests/test_db.py
@@ -11,6 +11,7 @@ class TestDB(BaseTestCase):
 
     def setUp(self):
         BaseTestCase.setUp(self)
+        self.odoo.logout()
         self.databases = []     # Keep databases created during tests
 
     def test_db_dump(self):
diff --git a/odoorpc/tests/test_field_binary.py b/odoorpc/tests/test_field_binary.py
new file mode 100644
index 0000000..bbe6871
--- /dev/null
+++ b/odoorpc/tests/test_field_binary.py
@@ -0,0 +1,38 @@
+# -*- coding: UTF-8 -*-
+
+import base64
+
+from odoorpc.tests import LoginTestCase
+
+
+class TestFieldBinary(LoginTestCase):
+
+    def test_field_binary_read(self):
+        img = self.user.image
+        base64.b64decode(img.encode('ascii'))
+
+    def test_field_binary_write(self):
+        backup = self.user.image
+        jpeg_file = (
+            b"\xff\xd8\xff\xdb\x00\x43\x00\x03\x02\x02\x02\x02\x02\x03\x02\x02"
+            b"\x02\x03\x03\x03\x03\x04\x06\x04\x04\x04\x04\x04\x08\x06\x06\x05"
+            b"\x06\x09\x08\x0a\x0a\x09\x08\x09\x09\x0a\x0c\x0f\x0c\x0a\x0b\x0e"
+            b"\x0b\x09\x09\x0d\x11\x0d\x0e\x0f\x10\x10\x11\x10\x0a\x0c\x12\x13"
+            b"\x12\x10\x13\x0f\x10\x10\x10\xff\xc9\x00\x0b\x08\x00\x01\x00\x01"
+            b"\x01\x01\x11\x00\xff\xcc\x00\x06\x00\x10\x10\x05\xff\xda\x00\x08"
+            b"\x01\x01\x00\x00\x3f\x00\xd2\xcf\x20\xff\xd9"
+        )  # https://github.com/mathiasbynens/small/blob/master/jpeg.jpg
+
+        self.user.image = base64.b64encode(jpeg_file).decode('ascii')
+        data = self.user.read(['image'])[0]
+        decoded = base64.b64decode(data['image'].encode('ascii'))
+        self.assertEqual(decoded, jpeg_file)
+
+        # Restore original value
+        self.user.image = backup
+        data = self.user.read(['image'])[0]
+        self.assertEqual(data['image'], backup)
+        self.assertEqual(self.user.image, backup)
+
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/odoorpc/tests/test_field_many2many.py b/odoorpc/tests/test_field_many2many.py
index 138cbe4..315df25 100644
--- a/odoorpc/tests/test_field_many2many.py
+++ b/odoorpc/tests/test_field_many2many.py
@@ -11,10 +11,17 @@ class TestFieldMany2many(LoginTestCase):
     def setUp(self):
         LoginTestCase.setUp(self)
         self.group_obj = self.odoo.env['res.groups']
-        self.u0_id = self.user_obj.create(
-            {'name': "TestMany2many", 'login': 'test_m2m_%s' % time.time()})
+        self.u0_id = self.user_obj.create({
+            'name': "TestMany2many User 1",
+            'login': 'test_m2m_u1_%s' % time.time(),
+        })
         self.g1_id = self.group_obj.create({'name': "Group 1"})
         self.g2_id = self.group_obj.create({'name': "Group 2"})
+        self.u1_id = self.user_obj.create({
+            'name': "TestMany2many User 2",
+            'login': 'test_m2m_u2_%s' % time.time(),
+            'groups_id': [(4, self.g1_id), (4, self.g2_id)],
+        })
 
     def test_field_many2many_read(self):
         self.assertIsInstance(self.user.company_ids, Model)
@@ -123,30 +130,28 @@ class TestFieldMany2many(LoginTestCase):
         self.assertIn(self.g2_id, group_ids)
 
     def test_field_many2many_write_isub_id(self):
-        user = self.user_obj.browse(self.u0_id)
-        group_id = user.read(['groups_id'])[0]['groups_id'][0]
+        user = self.user_obj.browse(self.u1_id)
+        self.assertIn(self.g1_id, user.groups_id.ids)
         # -= ID
-        user.groups_id -= group_id
+        user.groups_id -= self.g1_id
         data = user.read(['groups_id'])[0]
-        self.assertNotIn(group_id, data['groups_id'])
+        self.assertNotIn(self.g1_id, data['groups_id'])
         group_ids = [grp.id for grp in user.groups_id]
-        self.assertNotIn(group_id, group_ids)
+        self.assertNotIn(self.g1_id, group_ids)
 
     def test_field_many2many_write_isub_record(self):
-        user = self.user_obj.browse(self.u0_id)
-        group = user.groups_id[0]
+        user = self.user_obj.browse(self.u1_id)
+        self.assertIn(self.g1_id, user.groups_id.ids)
         # -= Record
-        data = user.read(['groups_id'])[0]
-        self.assertIn(group.id, data['groups_id'])
+        group = self.group_obj.browse(self.g1_id)
         user.groups_id -= group
         data = user.read(['groups_id'])[0]
         self.assertNotIn(group.id, data['groups_id'])
-        group_ids = [grp.id for grp in user.groups_id]
-        self.assertNotIn(group.id, group_ids)
+        self.assertNotIn(group.id, user.groups_id.ids)
 
     def test_field_many2many_write_isub_recordset(self):
-        user = self.user_obj.browse(self.u0_id)
-        groups = user.groups_id
+        user = self.user_obj.browse(self.u1_id)
+        groups = self.group_obj.browse([self.g1_id, self.g2_id])
         # -= Recordset
         data = user.read(['groups_id'])[0]
         self.assertIn(groups.ids[0], data['groups_id'])
@@ -160,8 +165,8 @@ class TestFieldMany2many(LoginTestCase):
         self.assertNotIn(groups.ids[1], group_ids)
 
     def test_field_many2many_write_isub_list_ids(self):
-        user = self.user_obj.browse(self.u0_id)
-        groups = user.groups_id
+        user = self.user_obj.browse(self.u1_id)
+        groups = self.group_obj.browse([self.g1_id, self.g2_id])
         # -= List of IDs
         data = user.read(['groups_id'])[0]
         self.assertIn(groups.ids[0], data['groups_id'])
@@ -175,8 +180,8 @@ class TestFieldMany2many(LoginTestCase):
         self.assertNotIn(groups.ids[1], group_ids)
 
     def test_field_many2many_write_isub_list_records(self):
-        user = self.user_obj.browse(self.u0_id)
-        groups = user.groups_id
+        user = self.user_obj.browse(self.u1_id)
+        groups = self.group_obj.browse([self.g1_id, self.g2_id])
         # -= List of records
         data = user.read(['groups_id'])[0]
         self.assertIn(groups.ids[0], data['groups_id'])
@@ -190,8 +195,8 @@ class TestFieldMany2many(LoginTestCase):
         self.assertNotIn(groups.ids[1], group_ids)
 
     def test_field_many2many_write_isub_id_and_list_ids(self):
-        user = self.user_obj.browse(self.u0_id)
-        groups = user.groups_id
+        user = self.user_obj.browse(self.u1_id)
+        groups = self.group_obj.browse([self.g1_id, self.g2_id])
         # -= ID and -= [ID]
         data = user.read(['groups_id'])[0]
         self.assertIn(groups.ids[0], data['groups_id'])
diff --git a/odoorpc/tests/test_field_reference.py b/odoorpc/tests/test_field_reference.py
index 5c0e52f..67f9e6c 100644
--- a/odoorpc/tests/test_field_reference.py
+++ b/odoorpc/tests/test_field_reference.py
@@ -2,25 +2,41 @@
 
 from odoorpc.tests import LoginTestCase
 from odoorpc.models import Model
+from odoorpc.tools import v
 
 
 class TestFieldReference(LoginTestCase):
 
     def test_field_reference_read(self):
-        Claim = self.odoo.env['crm.claim']
-        claim_id = Claim.search([])[0]
-        # Test field containing a value
-        self.odoo.execute(
-            'crm.claim', 'write', [claim_id], {'ref': 'res.partner,1'})
-        claim = Claim.browse(claim_id)
-        self.assertIsInstance(claim.ref, Model)
-        self.assertEqual(claim.ref._name, 'res.partner')
-        self.assertEqual(claim.ref.id, 1)
-        # Test if empty field returns False (unable to guess the model to use)
-        self.odoo.execute(
-            'crm.claim', 'write', [claim_id], {'ref': None})
-        claim = Claim.browse(claim_id)
-        self.assertEqual(claim.ref, False)
+        # 8.0 and 9.0
+        if v(self.odoo.version) < v('10'):
+            Claim = self.odoo.env['crm.claim']
+            claim_id = Claim.search([])[0]
+            # Test field containing a value
+            self.odoo.execute(
+                'crm.claim', 'write', [claim_id], {'ref': 'res.partner,1'})
+            claim = Claim.browse(claim_id)
+            self.assertIsInstance(claim.ref, Model)
+            self.assertEqual(claim.ref._name, 'res.partner')
+            self.assertEqual(claim.ref.id, 1)
+            # Test if empty field returns False (unable to guess the model to use)
+            self.odoo.execute(
+                'crm.claim', 'write', [claim_id], {'ref': None})
+            claim = Claim.browse(claim_id)
+            self.assertEqual(claim.ref, False)
+        # 10.0
+        else:
+            Subscription = self.odoo.env['subscription.subscription']
+            fields_list = list(Subscription.fields_get([]))
+            vals = Subscription.default_get(fields_list)
+            vals['name'] = "ODOORPC TEST (fields.Reference)"
+            vals['doc_source'] = 'res.partner,1'
+            subscription_id = Subscription.create(vals)
+            # Test field containing a value
+            subscription = Subscription.browse(subscription_id)
+            self.assertIsInstance(subscription.doc_source, Model)
+            self.assertEqual(subscription.doc_source._name, 'res.partner')
+            self.assertEqual(subscription.doc_source.id, 1)
 
     def test_field_reference_write(self):
         # TODO
diff --git a/odoorpc/tests/test_init.py b/odoorpc/tests/test_init.py
index 3d6a167..c81a489 100644
--- a/odoorpc/tests/test_init.py
+++ b/odoorpc/tests/test_init.py
@@ -35,6 +35,16 @@ class TestInit(BaseTestCase):
         self.assertEqual(odoo.port, self.env['port'])
         self.assertEqual(odoo.config['timeout'], 42)
 
+    def test_init_timeout_none(self):
+        odoo = odoorpc.ODOO(
+            self.env['host'], self.env['protocol'], self.env['port'], None)
+        self.assertIs(odoo.config['timeout'], None)
+
+    def test_init_timeout_float(self):
+        odoo = odoorpc.ODOO(
+            self.env['host'], self.env['protocol'], self.env['port'], 23.42)
+        self.assertEqual(odoo.config['timeout'], 23.42)
+
     def test_init_wrong_protocol(self):
         self.assertRaises(
             ValueError,
diff --git a/setup.py b/setup.py
index 312597c..489a064 100644
--- a/setup.py
+++ b/setup.py
... 9 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-odoorpc.git



More information about the Python-modules-commits mailing list