From 3dd3790597e84186d922b798aa8bb4650513ce4b Mon Sep 17 00:00:00 2001
From: Xavier Morel <xmo@odoo.com>
Date: Mon, 8 May 2017 16:15:02 +0200
Subject: [PATCH] [FIX] P3: raise exception with existing traceback

In Python 2, to raise a new exception but reuse a traceback requires a
special form of ``raise`` (``raise etype, evalue, tb``).

In Python 3, this is now done via a ``with_traceback`` method on
exception objects.

However this requires a bit of trickery as the former is invalid
syntax in Python 3, hence pycompat bridge created via an exec for
Python 2.
---
 addons/google_calendar/models/google_calendar.py | 2 +-
 odoo/addons/base/ir/ir_http.py                   | 2 +-
 odoo/addons/base/ir/ir_qweb/ir_qweb.py           | 2 +-
 odoo/addons/test_pylint/tests/test_pylint.py     | 6 ++++++
 odoo/service/server.py                           | 4 ++--
 odoo/tools/convert.py                            | 6 +++++-
 odoo/tools/pycompat.py                           | 7 +++++++
 odoo/tools/safe_eval.py                          | 8 ++++----
 8 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/addons/google_calendar/models/google_calendar.py b/addons/google_calendar/models/google_calendar.py
index d8e136faf533..f60ce78ef3d4 100644
--- a/addons/google_calendar/models/google_calendar.py
+++ b/addons/google_calendar/models/google_calendar.py
@@ -802,7 +802,7 @@ class GoogleCalendar(models.AbstractModel):
                     if actSrc == 'GG':
                         self.create_from_google(event, my_partner_id)
                     elif actSrc == 'OE':
-                        raise "Should be never here, creation for OE is done before update !"
+                        raise AssertionError("Should be never here, creation for OE is done before update !")
                     #TODO Add to batch
                 elif isinstance(actToDo, Update):
                     if actSrc == 'GG':
diff --git a/odoo/addons/base/ir/ir_http.py b/odoo/addons/base/ir/ir_http.py
index aa23531055ee..ff4654cf6c94 100644
--- a/odoo/addons/base/ir/ir_http.py
+++ b/odoo/addons/base/ir/ir_http.py
@@ -356,6 +356,6 @@ def convert_exception_to(to_type, with_message=False):
         else:
             message = str(with_message)
 
-        raise to_type, message, tb
+        raise pycompat.reraise(to_type, to_type(message), tb)
     except to_type as e:
         return e
diff --git a/odoo/addons/base/ir/ir_qweb/ir_qweb.py b/odoo/addons/base/ir/ir_qweb/ir_qweb.py
index 5548fcd47d8d..19119891ec44 100644
--- a/odoo/addons/base/ir/ir_qweb/ir_qweb.py
+++ b/odoo/addons/base/ir/ir_qweb/ir_qweb.py
@@ -127,7 +127,7 @@ class IrQWeb(models.AbstractModel, QWeb):
     def _compile_directive_call_assets(self, el, options):
         """ This special 't-call' tag can be used in order to aggregate/minify javascript and css assets"""
         if len(el):
-            raise "t-call-assets cannot contain children nodes"
+            raise SyntaxError("t-call-assets cannot contain children nodes")
 
         # self._get_asset(xmlid, options, css=css, js=js, debug=values.get('debug'), async=async, values=values)
         return [
diff --git a/odoo/addons/test_pylint/tests/test_pylint.py b/odoo/addons/test_pylint/tests/test_pylint.py
index 0def4516dc22..c2d1f2cf457d 100644
--- a/odoo/addons/test_pylint/tests/test_pylint.py
+++ b/odoo/addons/test_pylint/tests/test_pylint.py
@@ -42,6 +42,12 @@ class TestPyLint(TransactionCase):
         'parameter-unpacking',
 
         'metaclass-assignment',
+
+        'exception-message-attribute',
+        'indexing-exception',
+        'old-raise-syntax',
+        'raising-string',
+        'unpacking-in-except',
     ]
 
     BAD_FUNCTIONS = [
diff --git a/odoo/service/server.py b/odoo/service/server.py
index fa6ed422f817..cd1ae39491f5 100644
--- a/odoo/service/server.py
+++ b/odoo/service/server.py
@@ -550,7 +550,7 @@ class PreforkServer(CommonServer):
                     if e.errno not in [errno.EAGAIN]:
                         raise
         except select.error as e:
-            if e[0] not in [errno.EINTR]:
+            if e.args[0] not in [errno.EINTR]:
                 raise
 
     def start(self):
@@ -660,7 +660,7 @@ class Worker(object):
         try:
             select.select([self.multi.socket], [], [], self.multi.beat)
         except select.error as e:
-            if e[0] not in [errno.EINTR]:
+            if e.args[0] not in [errno.EINTR]:
                 raise
 
     def process_limit(self):
diff --git a/odoo/tools/convert.py b/odoo/tools/convert.py
index 76c7ec523af5..93684b3514fc 100644
--- a/odoo/tools/convert.py
+++ b/odoo/tools/convert.py
@@ -783,7 +783,11 @@ form: module.record_id""" % (xml_id,)
                 except Exception as e:
                     self.cr.rollback()
                     exc_info = sys.exc_info()
-                    raise ParseError, (ustr(e), etree.tostring(rec).rstrip(), rec.getroottree().docinfo.URL, rec.sourceline), exc_info[2]
+                    pycompat.reraise(
+                        ParseError,
+                        ParseError(ustr(e), etree.tostring(rec).rstrip(), rec.getroottree().docinfo.URL, rec.sourceline),
+                        exc_info[2]
+                    )
         return True
 
     def __init__(self, cr, module, idref, mode, report=None, noupdate=False, xml_filename=None):
diff --git a/odoo/tools/pycompat.py b/odoo/tools/pycompat.py
index 3fbb847a9fac..7ce4f45773a1 100644
--- a/odoo/tools/pycompat.py
+++ b/odoo/tools/pycompat.py
@@ -20,6 +20,8 @@ if PY2:
         cls.next = cls.__next__
         del cls.__next__
         return cls
+
+    exec ('def reraise(tp, value, tb=None):\n raise tp, value, tb')
 else:
     # pylint: disable=bad-functions
     integer_types = (int,)
@@ -34,3 +36,8 @@ else:
 
     def implements_iterator(cls):
         return cls
+
+    def reraise(tp, value, tb=None):
+        if value.__traceback__ != tb:
+            raise value.with_traceback(tb)
+        raise value
diff --git a/odoo/tools/safe_eval.py b/odoo/tools/safe_eval.py
index 1897486eb82f..569df6455e2b 100644
--- a/odoo/tools/safe_eval.py
+++ b/odoo/tools/safe_eval.py
@@ -21,8 +21,10 @@ import functools
 from psycopg2 import OperationalError
 from types import CodeType
 import logging
+import sys
 import werkzeug
 
+from . import pycompat
 from .misc import ustr
 
 import odoo
@@ -159,9 +161,8 @@ def test_expr(expr, allowed_codes, mode="eval"):
     except (SyntaxError, TypeError, ValueError):
         raise
     except Exception as e:
-        import sys
         exc_info = sys.exc_info()
-        raise ValueError, '"%s" while compiling\n%r' % (ustr(e), expr), exc_info[2]
+        pycompat.reraise(ValueError, ValueError('"%s" while compiling\n%r' % (ustr(e), expr)), exc_info[2])
     assert_valid_codeobj(allowed_codes, code_obj, expr)
     return code_obj
 
@@ -320,9 +321,8 @@ def safe_eval(expr, globals_dict=None, locals_dict=None, mode="eval", nocopy=Fal
     except odoo.exceptions.MissingError:
         raise
     except Exception as e:
-        import sys
         exc_info = sys.exc_info()
-        raise ValueError, '%s: "%s" while evaluating\n%r' % (ustr(type(e)), ustr(e), expr), exc_info[2]
+        pycompat.reraise(ValueError, ValueError('%s: "%s" while evaluating\n%r' % (ustr(type(e)), ustr(e), expr)), exc_info[2])
 def test_python_expr(expr, mode="eval"):
     try:
         test_expr(expr, _SAFE_OPCODES, mode=mode)
-- 
GitLab