summaryrefslogtreecommitdiff
path: root/odoo
diff options
context:
space:
mode:
authorxmo-odoo <xmo@odoo.com>2017-04-27 13:59:33 +0200
committerGitHub <noreply@github.com>2017-04-27 13:59:33 +0200
commit2e6a589f417af48e3322955ffff6e94b6d8a24e3 (patch)
treeaa613ecc1f74a9531a03de89aa2bdc7bb32eed3b /odoo
parentde4a2216b953abb86094c9bfa5f45b1eaaa79d3d (diff)
[FIX] builtins removed from Python 3
* Reverse wrapper courtesy of @rco-odoo's original P3 branch * thin compat module stripped down from werkzeug (to augment as needed) issue 8530
Diffstat (limited to 'odoo')
-rw-r--r--odoo/addons/base/ir/ir_model.py3
-rw-r--r--odoo/addons/base/ir/ir_qweb/ir_qweb.py3
-rw-r--r--odoo/addons/base/ir/ir_qweb/qweb.py5
-rw-r--r--odoo/addons/base/ir/ir_translation.py3
-rw-r--r--odoo/addons/base/ir/ir_ui_menu.py4
-rw-r--r--odoo/addons/base/ir/ir_ui_view.py6
-rw-r--r--odoo/addons/base/res/ir_property.py3
-rw-r--r--odoo/addons/base/tests/test_api.py6
-rw-r--r--odoo/addons/base/tests/test_expression.py3
-rw-r--r--odoo/addons/base/tests/test_float.py13
-rw-r--r--odoo/addons/base/tests/test_ir_sequence.py4
-rw-r--r--odoo/addons/base/tests/test_ir_sequence_date_range.py8
-rw-r--r--odoo/addons/base/tests/test_misc.py4
-rw-r--r--odoo/addons/base/tests/test_orm.py4
-rw-r--r--odoo/addons/base/tests/test_res_config.py3
-rw-r--r--odoo/addons/test_limits/models.py4
-rw-r--r--odoo/addons/test_new_api/tests/test_attributes.py3
-rw-r--r--odoo/addons/test_pylint/tests/test_pylint.py15
-rw-r--r--odoo/fields.py5
-rw-r--r--odoo/http.py19
-rw-r--r--odoo/models.py9
-rw-r--r--odoo/modules/graph.py2
-rw-r--r--odoo/modules/migration.py3
-rw-r--r--odoo/modules/module.py2
-rw-r--r--odoo/osv/expression.py3
-rw-r--r--odoo/service/model.py5
-rw-r--r--odoo/service/server.py2
-rw-r--r--odoo/sql_db.py8
-rw-r--r--odoo/tests/common.py2
-rw-r--r--odoo/tools/config.py2
-rw-r--r--odoo/tools/convert.py6
-rw-r--r--odoo/tools/float_utils.py16
-rwxr-xr-xodoo/tools/graph.py2
-rw-r--r--odoo/tools/image.py4
-rw-r--r--odoo/tools/import_email.py2
-rw-r--r--odoo/tools/misc.py46
-rw-r--r--odoo/tools/pycompat.py31
-rw-r--r--odoo/tools/safe_eval.py9
-rw-r--r--odoo/tools/test_reports.py6
-rw-r--r--odoo/tools/translate.py6
40 files changed, 186 insertions, 98 deletions
diff --git a/odoo/addons/base/ir/ir_model.py b/odoo/addons/base/ir/ir_model.py
index 4c64a172057..79118c845f2 100644
--- a/odoo/addons/base/ir/ir_model.py
+++ b/odoo/addons/base/ir/ir_model.py
@@ -10,6 +10,7 @@ from odoo import api, fields, models, SUPERUSER_ID, tools, _
from odoo.exceptions import AccessError, UserError, ValidationError
from odoo.modules.registry import Registry
from odoo.osv import expression
+from odoo.tools import pycompat
from odoo.tools.safe_eval import safe_eval
_logger = logging.getLogger(__name__)
@@ -1055,7 +1056,7 @@ class IrModelAccess(models.Model):
else:
model_name = model
- if isinstance(group_ids, (int, long)):
+ if isinstance(group_ids, pycompat.integer_types):
group_ids = [group_ids]
query = """ SELECT 1 FROM ir_model_access a
diff --git a/odoo/addons/base/ir/ir_qweb/ir_qweb.py b/odoo/addons/base/ir/ir_qweb/ir_qweb.py
index dc71f3304ab..20a640be8d4 100644
--- a/odoo/addons/base/ir/ir_qweb/ir_qweb.py
+++ b/odoo/addons/base/ir/ir_qweb/ir_qweb.py
@@ -4,6 +4,7 @@ import ast
from urlparse import urlparse
from lxml import html
+from odoo.tools import pycompat
from .qweb import QWeb, Contextifier
from .assetsbundle import AssetsBundle
from lxml import etree
@@ -90,7 +91,7 @@ class IrQWeb(models.AbstractModel, QWeb):
view = self.env['ir.ui.view'].browse(view_id)
return view.inherit_id is not None
- if isinstance(name, (int, long)) or is_child_view(name):
+ if isinstance(name, pycompat.integer_types) or is_child_view(name):
for node in etree.fromstring(template):
if node.get('t-name'):
node.set('t-name', str(name))
diff --git a/odoo/addons/base/ir/ir_qweb/qweb.py b/odoo/addons/base/ir/ir_qweb/qweb.py
index 0c69bd90baa..a4204326344 100644
--- a/odoo/addons/base/ir/ir_qweb/qweb.py
+++ b/odoo/addons/base/ir/ir_qweb/qweb.py
@@ -11,6 +11,9 @@ from werkzeug.utils import escape as _escape
from itertools import chain, izip, tee
import __builtin__
from functools import reduce
+
+from odoo.tools import pycompat
+
builtin_defaults = {name: getattr(__builtin__, name) for name in dir(__builtin__)}
try:
@@ -160,7 +163,7 @@ def foreach_iterator(base_ctx, enum, name):
if not enum:
return
if isinstance(enum, int):
- enum = xrange(enum)
+ enum = pycompat.range(enum)
size = None
if isinstance(enum, Sized):
ctx["%s_size" % name] = size = len(enum)
diff --git a/odoo/addons/base/ir/ir_translation.py b/odoo/addons/base/ir/ir_translation.py
index bf580bbf3bf..7d73f40d65b 100644
--- a/odoo/addons/base/ir/ir_translation.py
+++ b/odoo/addons/base/ir/ir_translation.py
@@ -8,6 +8,7 @@ from difflib import get_close_matches
from odoo import api, fields, models, tools, SUPERUSER_ID, _
from odoo.exceptions import AccessError, UserError, ValidationError
from odoo.modules import get_module_path, get_module_resource
+from odoo.tools import pycompat
_logger = logging.getLogger(__name__)
@@ -395,7 +396,7 @@ class IrTranslation(models.Model):
if isinstance(types, basestring):
types = (types,)
if res_id:
- if isinstance(res_id, (int, long)):
+ if isinstance(res_id, pycompat.integer_types):
res_id = (res_id,)
else:
res_id = tuple(res_id)
diff --git a/odoo/addons/base/ir/ir_ui_menu.py b/odoo/addons/base/ir/ir_ui_menu.py
index 15ba7509700..c8a39322835 100644
--- a/odoo/addons/base/ir/ir_ui_menu.py
+++ b/odoo/addons/base/ir/ir_ui_menu.py
@@ -133,9 +133,9 @@ class IrUiMenu(models.Model):
if not self._context.get('ir.ui.menu.full_list'):
menus = menus._filter_visible_menus()
if offset:
- menus = menus[long(offset):]
+ menus = menus[offset:]
if limit:
- menus = menus[:long(limit)]
+ menus = menus[:limit]
return len(menus) if count else menus
@api.multi
diff --git a/odoo/addons/base/ir/ir_ui_view.py b/odoo/addons/base/ir/ir_ui_view.py
index 729d4a8364d..c557d15ee6b 100644
--- a/odoo/addons/base/ir/ir_ui_view.py
+++ b/odoo/addons/base/ir/ir_ui_view.py
@@ -22,7 +22,7 @@ from odoo.exceptions import ValidationError
from odoo.http import request
from odoo.modules.module import get_resource_from_path, get_resource_path
from odoo.osv import orm
-from odoo.tools import config, graph, ConstantMapping, SKIPPED_ELEMENT_TYPES
+from odoo.tools import config, graph, ConstantMapping, SKIPPED_ELEMENT_TYPES, pycompat
from odoo.tools.convert import _fix_multiple_roots
from odoo.tools.parse_version import parse_version
from odoo.tools.safe_eval import safe_eval
@@ -944,7 +944,7 @@ actual arch.
view ID or an XML ID. Note that this method may be overridden for other
kinds of template values.
"""
- if isinstance(template, (int, long)):
+ if isinstance(template, pycompat.integer_types):
return template
if '.' not in template:
raise ValueError('Invalid template id: %r' % template)
@@ -1045,7 +1045,7 @@ actual arch.
@api.multi
def render(self, values=None, engine='ir.qweb'):
- assert isinstance(self.id, (int, long))
+ assert isinstance(self.id, pycompat.integer_types)
qcontext = dict(
env=self.env,
diff --git a/odoo/addons/base/res/ir_property.py b/odoo/addons/base/res/ir_property.py
index 4dcc33209f2..8e1b7eda860 100644
--- a/odoo/addons/base/res/ir_property.py
+++ b/odoo/addons/base/res/ir_property.py
@@ -5,6 +5,7 @@ from operator import itemgetter
from odoo import api, fields, models, _
from odoo.exceptions import UserError
+from odoo.tools import pycompat
TYPE2FIELD = {
'char': 'value_text',
@@ -70,7 +71,7 @@ class Property(models.Model):
if field == 'value_reference':
if isinstance(value, models.BaseModel):
value = '%s,%d' % (value._name, value.id)
- elif isinstance(value, (int, long)):
+ elif isinstance(value, pycompat.integer_types):
field_id = values.get('fields_id')
if not field_id:
if not prop:
diff --git a/odoo/addons/base/tests/test_api.py b/odoo/addons/base/tests/test_api.py
index cbb63daec59..8270d6086d5 100644
--- a/odoo/addons/base/tests/test_api.py
+++ b/odoo/addons/base/tests/test_api.py
@@ -2,7 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models
-from odoo.tools import mute_logger
+from odoo.tools import mute_logger, pycompat
from odoo.tests import common
from odoo.exceptions import AccessError
@@ -69,8 +69,8 @@ class TestAPI(common.TransactionCase):
self.cr.execute("SELECT COUNT(*) FROM res_partner WHERE active")
count1 = self.cr.fetchone()[0]
count2 = self.env['res.partner'].search([], count=True)
- self.assertIsInstance(count1, (int, long))
- self.assertIsInstance(count2, (int, long))
+ self.assertIsInstance(count1, pycompat.integer_types)
+ self.assertIsInstance(count2, pycompat.integer_types)
self.assertEqual(count1, count2)
@mute_logger('odoo.models')
diff --git a/odoo/addons/base/tests/test_expression.py b/odoo/addons/base/tests/test_expression.py
index 104c4a6dfe1..4dea4797b0c 100644
--- a/odoo/addons/base/tests/test_expression.py
+++ b/odoo/addons/base/tests/test_expression.py
@@ -214,9 +214,8 @@ class TestExpression(TransactionCase):
# create new company with partners, and partners with no company
company2 = self.env['res.company'].create({'name': 'Acme 2'})
- for i in xrange(4):
+ for i in range(4):
Partner.create({'name': 'P of Acme %s' % i, 'company_id': company2.id})
- for i in xrange(4):
Partner.create({'name': 'P of All %s' % i, 'company_id': False})
# check if many2one works with negative empty list
diff --git a/odoo/addons/base/tests/test_float.py b/odoo/addons/base/tests/test_float.py
index 03e15b5877e..8c4ee380bd2 100644
--- a/odoo/addons/base/tests/test_float.py
+++ b/odoo/addons/base/tests/test_float.py
@@ -4,7 +4,7 @@
from math import log10
from odoo.tests.common import TransactionCase
-from odoo.tools import float_compare, float_is_zero, float_repr, float_round, float_split_str
+from odoo.tools import float_compare, float_is_zero, float_repr, float_round, float_split_str, pycompat
class TestFloatPrecision(TransactionCase):
@@ -98,14 +98,13 @@ class TestFloatPrecision(TransactionCase):
precisions = [2, 2, 2, 2, 2, 2, 3, 4]
# Note: max precision for double floats is 53 bits of precision or
# 17 significant decimal digits
- for magnitude in range(7):
- for i in xrange(len(fractions)):
- frac, exp, prec = fractions[i], expecteds[i], precisions[i]
+ for magnitude in pycompat.range(7):
+ for frac, exp, prec in zip(fractions, expecteds, precisions):
for sign in [-1,1]:
- for x in xrange(0,10000,97):
- n = x * 10**magnitude
+ for x in pycompat.range(0, 10000, 97):
+ n = x * 10 ** magnitude
f = sign * (n + frac)
- f_exp = ('-' if f != 0 and sign == -1 else '') + str(n) + exp
+ f_exp = ('-' if f != 0 and sign == -1 else '') + str(n) + exp
try_round(f, f_exp, digits=prec)
def try_zero(amount, expected):
diff --git a/odoo/addons/base/tests/test_ir_sequence.py b/odoo/addons/base/tests/test_ir_sequence.py
index 76db66d7008..946043d9f4b 100644
--- a/odoo/addons/base/tests/test_ir_sequence.py
+++ b/odoo/addons/base/tests/test_ir_sequence.py
@@ -154,7 +154,7 @@ class TestIrSequenceGenerate(unittest.TestCase):
self.assertTrue(seq)
with environment() as env:
- for i in xrange(1, 10):
+ for i in range(1, 10):
n = env['ir.sequence'].next_by_code('test_sequence_type_5')
self.assertEqual(n, str(i))
@@ -169,7 +169,7 @@ class TestIrSequenceGenerate(unittest.TestCase):
self.assertTrue(seq)
with environment() as env:
- for i in xrange(1, 10):
+ for i in range(1, 10):
n = env['ir.sequence'].next_by_code('test_sequence_type_6')
self.assertEqual(n, str(i))
diff --git a/odoo/addons/base/tests/test_ir_sequence_date_range.py b/odoo/addons/base/tests/test_ir_sequence_date_range.py
index 147b0f26050..7bd43eb4ea9 100644
--- a/odoo/addons/base/tests/test_ir_sequence_date_range.py
+++ b/odoo/addons/base/tests/test_ir_sequence_date_range.py
@@ -116,16 +116,16 @@ class TestIrSequenceDateRangeChangeImplementation(SingleTransactionCase):
seq = self.env['ir.sequence']
seq16 = self.env['ir.sequence'].with_context({'ir_sequence_date': january(16)})
- for i in xrange(1, 5):
+ for i in range(1, 5):
n = seq.next_by_code('test_sequence_date_range_3')
self.assertEqual(n, str(i))
- for i in xrange(1, 5):
+ for i in range(1, 5):
n = seq16.next_by_code('test_sequence_date_range_3')
self.assertEqual(n, str(i))
- for i in xrange(1, 5):
+ for i in range(1, 5):
n = seq.next_by_code('test_sequence_date_range_4')
self.assertEqual(n, str(i))
- for i in xrange(1, 5):
+ for i in range(1, 5):
n = seq16.next_by_code('test_sequence_date_range_4')
self.assertEqual(n, str(i))
diff --git a/odoo/addons/base/tests/test_misc.py b/odoo/addons/base/tests/test_misc.py
index b8ede104a7c..c148b901982 100644
--- a/odoo/addons/base/tests/test_misc.py
+++ b/odoo/addons/base/tests/test_misc.py
@@ -16,14 +16,14 @@ class TestCountingStream(unittest.TestCase):
self.assertEqual(s.index, 0)
def test_single(self):
- s = misc.CountingStream(xrange(1))
+ s = misc.CountingStream(range(1))
self.assertEqual(s.index, -1)
self.assertEqual(next(s, None), 0)
self.assertIsNone(next(s, None))
self.assertEqual(s.index, 1)
def test_full(self):
- s = misc.CountingStream(xrange(42))
+ s = misc.CountingStream(range(42))
for _ in s:
pass
self.assertEqual(s.index, 42)
diff --git a/odoo/addons/base/tests/test_orm.py b/odoo/addons/base/tests/test_orm.py
index ef586218a0d..0da71a84ad5 100644
--- a/odoo/addons/base/tests/test_orm.py
+++ b/odoo/addons/base/tests/test_orm.py
@@ -5,7 +5,7 @@ from collections import defaultdict
from odoo.exceptions import AccessError, MissingError
from odoo.tests.common import TransactionCase
-from odoo.tools import mute_logger
+from odoo.tools import mute_logger, pycompat
class TestORM(TransactionCase):
@@ -193,7 +193,7 @@ class TestInherits(TransactionCase):
""" `default_get` cannot return a dictionary or a new id """
defaults = self.env['res.users'].default_get(['partner_id'])
if 'partner_id' in defaults:
- self.assertIsInstance(defaults['partner_id'], (bool, int, long))
+ self.assertIsInstance(defaults['partner_id'], (bool, pycompat.integer_types))
def test_create(self):
""" creating a user should automatically create a new partner """
diff --git a/odoo/addons/base/tests/test_res_config.py b/odoo/addons/base/tests/test_res_config.py
index af919ce4b66..89300bf43a5 100644
--- a/odoo/addons/base/tests/test_res_config.py
+++ b/odoo/addons/base/tests/test_res_config.py
@@ -3,6 +3,7 @@
from odoo import exceptions
from odoo.tests.common import TransactionCase
+from odoo.tools import pycompat
class TestResConfig(TransactionCase):
@@ -42,7 +43,7 @@ class TestResConfig(TransactionCase):
self.assertIsInstance(res, tuple)
self.assertEqual(len(res), 2, "The result should contain 2 elements")
self.assertIsInstance(res[0], basestring)
- self.assertIsInstance(res[1], (int, long))
+ self.assertIsInstance(res[1], pycompat.integer_types)
# Check returned values
self.assertEqual(res[0], self.expected_path)
diff --git a/odoo/addons/test_limits/models.py b/odoo/addons/test_limits/models.py
index f46402857cf..506578a811b 100644
--- a/odoo/addons/test_limits/models.py
+++ b/odoo/addons/test_limits/models.py
@@ -2,8 +2,10 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import time
+import sys
from odoo import models, api
+from odoo.tools import pycompat
class m(models.Model):
""" This model exposes a few methods that will consume between 'almost no
@@ -37,7 +39,7 @@ class m(models.Model):
t0 = time.clock()
t1 = time.clock()
while t1 - t0 < seconds:
- for i in xrange(10000000):
+ for i in pycompat.range(10000000):
x = i * i
t1 = time.clock()
return True
diff --git a/odoo/addons/test_new_api/tests/test_attributes.py b/odoo/addons/test_new_api/tests/test_attributes.py
index 636dadf2a06..b37afe7e30d 100644
--- a/odoo/addons/test_new_api/tests/test_attributes.py
+++ b/odoo/addons/test_new_api/tests/test_attributes.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from odoo.tests import common
+from odoo.tools import pycompat
ANSWER_TO_ULTIMATE_QUESTION = 42
@@ -16,7 +17,7 @@ class TestAttributes(common.TransactionCase):
self.assertTrue(hasattr(instance, 'unknown'))
# Is it the right type ?
- self.assertIsInstance(instance.unknown, (int, long))
+ self.assertIsInstance(instance.unknown, pycompat.integer_types)
# Is it the right value, in case of, we don't know ;-)
self.assertEqual(instance.unknown, ANSWER_TO_ULTIMATE_QUESTION)
diff --git a/odoo/addons/test_pylint/tests/test_pylint.py b/odoo/addons/test_pylint/tests/test_pylint.py
index 38fa4c3d51a..02c1a14a261 100644
--- a/odoo/addons/test_pylint/tests/test_pylint.py
+++ b/odoo/addons/test_pylint/tests/test_pylint.py
@@ -25,6 +25,21 @@ class TestPyLint(TransactionCase):
'E0601', # using variable before assignment
'W0123', # eval used
'W0101', # unreachable code
+
+ 'long-suffix',
+ 'apply-builtin',
+ 'cmp-builtin',
+ 'coerce-builtin',
+ 'execfile-builtin',
+ 'input-builtin',
+ 'intern-builtin',
+ 'long-builtin',
+ 'raw_input-builtin',
+ 'reload-builtin',
+ 'xrange-builtin',
+ # TODO: enable once report has been removed
+ # 'file-builtin',
+ # 'reduce-builtin',
]
def _skip_test(self, reason):
diff --git a/odoo/fields.py b/odoo/fields.py
index 2b289227f9f..d713167a101 100644
--- a/odoo/fields.py
+++ b/odoo/fields.py
@@ -15,8 +15,7 @@ import xmlrpclib
import psycopg2
from odoo.sql_db import LazyCursor
-from odoo.tools import float_precision, float_repr, float_round, frozendict, \
- html_sanitize, human_size, pg_varchar, ustr, OrderedSet
+from odoo.tools import float_precision, float_repr, float_round, frozendict, html_sanitize, human_size, pg_varchar, ustr, OrderedSet, pycompat
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT as DATETIME_FORMAT
from odoo.tools.translate import html_translate, _
@@ -1656,7 +1655,7 @@ class Binary(Field):
def convert_to_cache(self, value, record, validate=True):
if isinstance(value, buffer):
return str(value)
- if isinstance(value, (int, long)) and \
+ if isinstance(value, pycompat.integer_types) and \
(record._context.get('bin_size') or
record._context.get('bin_size_' + self.name)):
# If the client requests only the size of the field, we return that
diff --git a/odoo/http.py b/odoo/http.py
index a8dbf098576..9eb9e75e101 100644
--- a/odoo/http.py
+++ b/odoo/http.py
@@ -621,10 +621,10 @@ class JsonRequest(WebRequest):
# We need then to manage http sessions manually.
response['session_id'] = self.session.sid
mime = 'application/javascript'
- body = "%s(%s);" % (self.jsonp, json.dumps(response),)
+ body = "%s(%s);" % (self.jsonp, json.dumps(response, default=ustr),)
else:
mime = 'application/json'
- body = json.dumps(response)
+ body = json.dumps(response, default=ustr)
return Response(
body, headers=[('Content-Type', mime),
@@ -695,7 +695,7 @@ def serialize_exception(e):
"name": type(e).__module__ + "." + type(e).__name__ if type(e).__module__ else type(e).__name__,
"debug": traceback.format_exc(),
"message": ustr(e),
- "arguments": to_jsonable(e.args),
+ "arguments": e.args,
"exception_type": "internal_error"
}
if isinstance(e, odoo.exceptions.UserError):
@@ -716,19 +716,6 @@ def serialize_exception(e):
tmp["exception_type"] = "except_orm"
return tmp
-def to_jsonable(o):
- if isinstance(o, str) or isinstance(o,unicode) or isinstance(o, int) or isinstance(o, long) \
- or isinstance(o, bool) or o is None or isinstance(o, float):
- return o
- if isinstance(o, list) or isinstance(o, tuple):
- return [to_jsonable(x) for x in o]
- if isinstance(o, dict):
- tmp = {}
- for k, v in o.items():
- tmp[u"%s" % k] = to_jsonable(v)
- return tmp
- return ustr(o)
-
class HttpRequest(WebRequest):
""" Handler for the ``http`` request type.
diff --git a/odoo/models.py b/odoo/models.py
index fe302fb0a4f..e5e56b7ff76 100644
--- a/odoo/models.py
+++ b/odoo/models.py
@@ -41,6 +41,7 @@ from lxml import etree
from lxml.builder import E
import odoo
+from odoo.tools import pycompat
from . import SUPERUSER_ID
from . import api
from . import tools
@@ -173,7 +174,7 @@ class NewId(object):
def __nonzero__(self):
return False
-IdType = (int, long, str, unicode, NewId)
+IdType = pycompat.integer_types + (str, unicode, NewId)
# maximum number of prefetched records
@@ -1391,7 +1392,7 @@ class BaseModel(object):
provided domain <reference/orm/domains>`.
"""
res = self.search(args, count=True)
- return res if isinstance(res, (int, long)) else len(res)
+ return res if isinstance(res, pycompat.integer_types) else len(res)
@api.model
@api.returns('self',
@@ -1536,7 +1537,7 @@ class BaseModel(object):
# override defaults with the provided values, never allow the other way around
defaults = self.default_get(list(missing_defaults))
for name, value in defaults.iteritems():
- if self._fields[name].type == 'many2many' and value and isinstance(value[0], (int, long)):
+ if self._fields[name].type == 'many2many' and value and isinstance(value[0], pycompat.integer_types):
# convert a list of ids into a list of commands
defaults[name] = [(6, 0, value)]
elif self._fields[name].type == 'one2many' and value and isinstance(value[0], dict):
@@ -3862,7 +3863,7 @@ class BaseModel(object):
"""
ids, new_ids = [], []
for i in self._ids:
- (ids if isinstance(i, (int, long)) else new_ids).append(i)
+ (ids if isinstance(i, pycompat.integer_types) else new_ids).append(i)
if not ids:
return self
query = """SELECT id FROM "%s" WHERE id IN %%s""" % self._table
diff --git a/odoo/modules/graph.py b/odoo/modules/graph.py
index ca4998fd254..9a11949c508 100644
--- a/odoo/modules/graph.py
+++ b/odoo/modules/graph.py
@@ -165,7 +165,7 @@ class Node(object):
for attr in ('init', 'update', 'demo'):
if hasattr(self, attr):
setattr(node, attr, True)
- self.children.sort(lambda x, y: cmp(x.name, y.name))
+ self.children.sort(key=lambda x: x.name)
return node
def __setattr__(self, name, value):
diff --git a/odoo/modules/migration.py b/odoo/modules/migration.py
index 552c9d8dae7..5b1dcf09ab2 100644
--- a/odoo/modules/migration.py
+++ b/odoo/modules/migration.py
@@ -137,7 +137,8 @@ class MigrationManager(object):
try:
fp, fname = tools.file_open(pyfile, pathinfo=True)
- if not isinstance(fp, file):
+ # FIXME: imp.load_source removed in P3, and so is the ``file`` object...
+ if not isinstance(fp, file):# pylint: disable=file-builtin
# imp.load_source need a real file object, so we create
# one from the file-like object we get from file_open
fp2 = os.tmpfile()
diff --git a/odoo/modules/module.py b/odoo/modules/module.py
index 398585ba239..dd1485e1d8a 100644
--- a/odoo/modules/module.py
+++ b/odoo/modules/module.py
@@ -78,7 +78,7 @@ class AddonsHook(object):
# execute source in context of module *after* putting everything in
# sys.modules, so recursive import works
- execfile(modfile, new_mod.__dict__)
+ exec(open(modfile, 'rb').read(), new_mod.__dict__)
# people import openerp.addons and expect openerp.addons.<module> to work
setattr(odoo.addons, addon_name, new_mod)
diff --git a/odoo/osv/expression.py b/odoo/osv/expression.py
index bef1cb1c523..b98fca44b39 100644
--- a/odoo/osv/expression.py
+++ b/odoo/osv/expression.py
@@ -121,6 +121,7 @@ from functools import partial
from zlib import crc32
import odoo.modules
+from odoo.tools import pycompat
from ..models import MAGIC_COLUMNS, BaseModel
import odoo.tools as tools
@@ -700,7 +701,7 @@ class expression(object):
names = [value]
elif value and isinstance(value, (tuple, list)) and all(isinstance(item, basestring) for item in value):
names = value
- elif isinstance(value, (int, long)):
+ elif isinstance(value, pycompat.integer_types):
return [value]
if names:
return list({
diff --git a/odoo/service/model.py b/odoo/service/model.py
index 6502f74d2bb..33a7fb2b93f 100644
--- a/odoo/service/model.py
+++ b/odoo/service/model.py
@@ -10,6 +10,7 @@ import time
import odoo
from odoo.exceptions import UserError, ValidationError, QWebException
from odoo.models import check_method_name
+from odoo.tools import pycompat
from odoo.tools.translate import translate
from odoo.tools.translate import _
@@ -63,7 +64,7 @@ def check(f):
uid = 1
- if args and isinstance(args[0], (long, int)):
+ if args and isinstance(args[0], pycompat.integer_types):
uid = args[0]
lang = ctx and ctx.get('lang')
@@ -83,7 +84,7 @@ def check(f):
if args and len(args) > 1:
# TODO self doesn't exist, but was already wrong before (it was not a registry but just the object_service.
obj = self.get(args[1])
- if len(args) > 3 and isinstance(args[3], (long, int, list)):
+ if len(args) > 3 and isinstance(args[3], (pycompat.integer_types, list)):
ids = args[3]
else:
ids = []
diff --git a/odoo/service/server.py b/odoo/service/server.py
index 97d99983597..5de54d8188e 100644
--- a/odoo/service/server.py
+++ b/odoo/service/server.py
@@ -863,7 +863,7 @@ def _reexec(updated_modules=None):
def load_test_file_yml(registry, test_file):
with registry.cursor() as cr:
- odoo.tools.convert_yaml_import(cr, 'base', file(test_file), 'test', {}, 'init')
+ odoo.tools.convert_yaml_import(cr, 'base', open(test_file, 'rb'), 'test', {}, 'init')
if config['test_commit']:
_logger.info('test %s has been commited', test_file)
cr.commit()
diff --git a/odoo/sql_db.py b/odoo/sql_db.py
index a7c7d6fc54d..214dbfca96c 100644
--- a/odoo/sql_db.py
+++ b/odoo/sql_db.py
@@ -21,6 +21,8 @@ import psycopg2.extensions
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_REPEATABLE_READ
from psycopg2.pool import PoolError
+from .tools import pycompat
+
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
_logger = logging.getLogger(__name__)
@@ -255,10 +257,8 @@ class Cursor(object):
sum = 0
if sqllogs[type]:
sqllogitems = sqllogs[type].items()
- sqllogitems.sort(key=lambda k: k[1][1])
_logger.debug("SQL LOG %s:", type)
- sqllogitems.sort(lambda x, y: cmp(x[1][0], y[1][0]))
- for r in sqllogitems:
+ for r in sorted(sqllogitems, key=lambda k: k[1]):
delay = timedelta(microseconds=r[1][1])
_logger.debug("table: %s: %s/%s", r[0], delay, r[1][0])
sum += r[1][1]
@@ -469,7 +469,7 @@ class LazyCursor(object):
if cr is None:
from odoo import registry
cr = self._cursor = registry(self.dbname).cursor()
- for _ in xrange(self._depth):
+ for _ in pycompat.range(self._depth):
cr.__enter__()
return getattr(cr, name)
diff --git a/odoo/tests/common.py b/odoo/tests/common.py
index c16ce8b0425..29bfdd79d0e 100644
--- a/odoo/tests/common.py
+++ b/odoo/tests/common.py
@@ -367,7 +367,7 @@ class HttpCase(TransactionCase):
_logger.info('phantomjs unlink localstorage %s', i)
os.unlink(i)
try:
- phantom = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=None)
+ phantom = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=None, close_fds=True)
except OSError:
raise unittest.SkipTest("PhantomJS not found")
result = False
diff --git a/odoo/tools/config.py b/odoo/tools/config.py
index c832c1980cd..4443bc7e6d7 100644
--- a/odoo/tools/config.py
+++ b/odoo/tools/config.py
@@ -549,7 +549,7 @@ class configmanager(object):
if not rc_exists and not os.path.exists(os.path.dirname(self.rcfile)):
os.makedirs(os.path.dirname(self.rcfile))
try:
- p.write(file(self.rcfile, 'w'))
+ p.write(open(self.rcfile, 'w'))
if not rc_exists:
os.chmod(self.rcfile, 0o600)
except IOError:
diff --git a/odoo/tools/convert.py b/odoo/tools/convert.py
index 3410b929bc6..3df1d20b50f 100644
--- a/odoo/tools/convert.py
+++ b/odoo/tools/convert.py
@@ -890,10 +890,10 @@ def convert_xml_import(cr, module, xmlfile, idref=None, mode='init', noupdate=Fa
if idref is None:
idref={}
- if isinstance(xmlfile, file):
- xml_filename = xmlfile.name
- else:
+ if isinstance(xmlfile, basestring):
xml_filename = xmlfile
+ else:
+ xml_filename = xmlfile.name
obj = xml_import(cr, module, idref, mode, report=report, noupdate=noupdate, xml_filename=xml_filename)
obj.parse(doc.getroot(), mode=mode)
return True
diff --git a/odoo/tools/float_utils.py b/odoo/tools/float_utils.py
index 959299e2c97..8c71d7a29b2 100644
--- a/odoo/tools/float_utils.py
+++ b/odoo/tools/float_utils.py
@@ -4,6 +4,9 @@
from __future__ import print_function
import math
+from odoo.tools import pycompat
+
+
def _float_check_precision(precision_digits=None, precision_rounding=None):
assert (precision_digits is not None or precision_rounding is not None) and \
not (precision_digits and precision_rounding),\
@@ -54,7 +57,7 @@ def float_round(value, precision_digits=None, precision_rounding=None, rounding_
epsilon_magnitude = math.log(abs(normalized_value), 2)
epsilon = 2**(epsilon_magnitude-53)
if rounding_method == 'HALF-UP':
- normalized_value += cmp(normalized_value,0) * epsilon
+ normalized_value += math.copysign(epsilon, normalized_value)
rounded_value = round(normalized_value) # round to integer
# TIE-BREAKING: UP (for ceiling operations)
@@ -66,7 +69,7 @@ def float_round(value, precision_digits=None, precision_rounding=None, rounding_
# restored.
elif rounding_method == 'UP':
- sign = cmp(normalized_value, 0)
+ sign = math.copysign(1.0, normalized_value)
normalized_value -= sign*epsilon
rounded_value = math.ceil(abs(normalized_value))*sign # ceil to integer
@@ -214,14 +217,13 @@ if __name__ == "__main__":
fractions = [.0, .015, .01499, .675, .67499, .4555, .4555, .45555]
expecteds = ['.00', '.02', '.01', '.68', '.67', '.46', '.456', '.4556']
precisions = [2, 2, 2, 2, 2, 2, 3, 4]
- for magnitude in range(7):
- for i in xrange(len(fractions)):
- frac, exp, prec = fractions[i], expecteds[i], precisions[i]
+ for magnitude in pycompat.range(7):
+ for frac, exp, prec in zip(fractions, expecteds, precisions):
for sign in [-1,1]:
- for x in xrange(0,10000,97):
+ for x in pycompat.range(0, 10000, 97):
n = x * 10**magnitude
f = sign * (n + frac)
- f_exp = ('-' if f != 0 and sign == -1 else '') + str(n) + exp
+ f_exp = ('-' if f != 0 and sign == -1 else '') + str(n) + exp
try_round(f, f_exp, precision_digits=prec)
stop = time.time()
diff --git a/odoo/tools/graph.py b/odoo/tools/graph.py
index 454a1dce98f..82fc0e0978a 100755
--- a/odoo/tools/graph.py
+++ b/odoo/tools/graph.py
@@ -634,7 +634,7 @@ class graph(object):
self.init_order(self.start, self.result[self.start]['x'])
for level in self.levels:
- self.levels[level].sort(lambda x, y: cmp(self.result[x]['y'], self.result[y]['y']))
+ self.levels[level].sort(key=lambda x: self.result[x]['y'])
self.order_heuristic()
self.process_order()
diff --git a/odoo/tools/image.py b/odoo/tools/image.py
index 952d6b25c4c..481abd3da02 100644
--- a/odoo/tools/image.py
+++ b/odoo/tools/image.py
@@ -280,6 +280,6 @@ if __name__=="__main__":
assert len(sys.argv)==3, 'Usage to Test: image.py SRC.png DEST.png'
- img = file(sys.argv[1],'rb').read().encode('base64')
+ img = open(sys.argv[1],'rb').read().encode('base64')
new = image_resize_image(img, (128,100))
- file(sys.argv[2], 'wb').write(new.decode('base64'))
+ open(sys.argv[2], 'wb').write(new.decode('base64'))
diff --git a/odoo/tools/import_email.py b/odoo/tools/import_email.py
index 4178ca14a06..74029c693eb 100644
--- a/odoo/tools/import_email.py
+++ b/odoo/tools/import_email.py
@@ -125,7 +125,7 @@ class ReceiverEmail2Event(object):
os.mkdir(newdir)
counter += 1
- fd = file(os.path.join(newdir, filename), 'w')
+ fd = open(os.path.join(newdir, filename), 'w')
fd.write(part.get_payload(decode=1))
fd.close()
else:
diff --git a/odoo/tools/misc.py b/odoo/tools/misc.py
index f080d3067ca..d90031e43eb 100644
--- a/odoo/tools/misc.py
+++ b/odoo/tools/misc.py
@@ -27,6 +27,7 @@ from cStringIO import StringIO
from collections import defaultdict, Iterable, Mapping, MutableSet, OrderedDict
from itertools import islice, izip, groupby, repeat
from lxml import etree
+
from which import which
from threading import local
import traceback
@@ -41,6 +42,7 @@ except ImportError:
from config import config
from cache import *
from .parse_version import parse_version
+from . import pycompat
import odoo
# get_encodings, ustr and exception_to_unicode were originally from tools.misc.
@@ -279,7 +281,7 @@ def flatten(list):
return r
def reverse_enumerate(l):
- """Like enumerate but in the other sens
+ """Like enumerate but in the other direction
Usage::
>>> a = ['a', 'b', 'c']
@@ -295,7 +297,7 @@ def reverse_enumerate(l):
File "<stdin>", line 1, in <module>
StopIteration
"""
- return izip(xrange(len(l)-1, -1, -1), reversed(l))
+ return izip(pycompat.range(len(l)-1, -1, -1), reversed(l))
def partition(pred, elems):
""" Return a pair equivalent to:
@@ -654,8 +656,11 @@ def posix_to_ldml(fmt, locale):
def split_every(n, iterable, piece_maker=tuple):
"""Splits an iterable into length-n pieces. The last piece will be shorter
if ``n`` does not evenly divide the iterable length.
- @param ``piece_maker``: function to build the pieces
- from the slices (tuple,list,...)
+
+ :param int n: maximum size of each generated chunk
+ :param Iterable iterable: iterable to chunk into pieces
+ :param piece_maker: callable taking an iterable and collecting each
+ chunk from its slice, *must consume the entire slice*.
"""
iterator = iter(iterable)
piece = piece_maker(islice(iterator, n))
@@ -990,6 +995,39 @@ class LastOrderedSet(OrderedSet):
OrderedSet.discard(self, elem)
OrderedSet.add(self, elem)
+def unique(it):
+ """ "Uniquifier" for the provided iterable: will output each element of
+ the iterable once.
+
+ The iterable's elements must be hashahble.
+
+ :param Iterable it:
+ :rtype: Iterator
+ """
+ seen = set()
+ for e in it:
+ if e not in seen:
+ seen.add(e)
+ yield e
+
+class Reverse(object):
+ """ Wraps a value and reverses its ordering, useful in key functions when
+ mixing ascending and descending sort on non-numeric data as the
+ ``reverse`` parameter can not do piecemeal reordering.
+ """
+ __slots__ = ['val']
+
+ def __init__(self, val):
+ self.val = val
+
+ def __eq__(self, other): return self.val == other.val
+ def __ne__(self, other): return self.val != other.val
+
+ def __ge__(self, other): return self.val <= other.val
+ def __gt__(self, other): return self.val < other.val
+ def __le__(self, other): return self.val >= other.val
+ def __lt__(self, other): return self.val > other.val
+
@contextmanager
def ignore(*exc):
try:
diff --git a/odoo/tools/pycompat.py b/odoo/tools/pycompat.py
new file mode 100644
index 00000000000..114f7f2bd87
--- /dev/null
+++ b/odoo/tools/pycompat.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+# to remove if we decide to add a dependency on six or future
+# very strongly inspired by https://github.com/pallets/werkzeug/blob/master/werkzeug/_compat.py
+import sys
+
+PY2 = sys.version_info[0]
+
+if PY2:
+ # pylint: disable=long-builtin,xrange-builtin
+ integer_types = (int, long)
+
+ range = xrange
+
+ # noinspection PyUnresolvedReferences
+ from itertools import imap, izip, ifilter
+
+ def implements_iterator(cls):
+ cls.next = cls.__next__
+ del cls.__next__
+ return cls
+else:
+ integer_types = (int,)
+
+ range = range
+
+ imap = map
+ izip = zip
+ ifilter = filter
+
+ def implements_iterator(cls):
+ return cls
diff --git a/odoo/tools/safe_eval.py b/odoo/tools/safe_eval.py
index 14020378c21..ebe97619e35 100644
--- a/odoo/tools/safe_eval.py
+++ b/odoo/tools/safe_eval.py
@@ -16,11 +16,14 @@ condition/math builtins.
# - safe_eval in tryton http://hg.tryton.org/hgwebdir.cgi/trytond/rev/bbb5f73319ad
from opcode import HAVE_ARGUMENT, opmap
+
+import functools
from psycopg2 import OperationalError
from types import CodeType
import logging
import werkzeug
+from odoo.tools import pycompat
from .misc import ustr
import odoo
@@ -226,7 +229,6 @@ _BUILTINS = {
'bool': bool,
'int': int,
'float': float,
- 'long': long,
'enumerate': enumerate,
'dict': dict,
'list': list,
@@ -236,7 +238,7 @@ _BUILTINS = {
'min': min,
'max': max,
'sum': sum,
- 'reduce': reduce,
+ 'reduce': functools.reduce,
'filter': filter,
'round': round,
'len': len,
@@ -246,11 +248,10 @@ _BUILTINS = {
'any': any,
'ord': ord,
'chr': chr,
- 'cmp': cmp,
'divmod': divmod,
'isinstance': isinstance,
'range': range,
- 'xrange': xrange,
+ 'xrange': pycompat.range,
'zip': zip,
'Exception': Exception,
}
diff --git a/odoo/tools/test_reports.py b/odoo/tools/test_reports.py
index ef09862bc01..c1f9af8bb55 100644
--- a/odoo/tools/test_reports.py
+++ b/odoo/tools/test_reports.py
@@ -11,6 +11,8 @@ import odoo
import odoo.report
import odoo.tools as tools
import logging
+
+from odoo.tools import pycompat
from odoo.tools.safe_eval import safe_eval
from subprocess import Popen, PIPE
import os
@@ -45,7 +47,7 @@ def try_report(cr, uid, rname, ids, data=None, context=None, our_module=None, re
raise ValueError("Report %s produced an empty result!" % rname)
if tools.config['test_report_directory']:
- file(os.path.join(tools.config['test_report_directory'], rname+ '.'+res_format), 'wb+').write(res_data)
+ open(os.path.join(tools.config['test_report_directory'], rname+ '.'+res_format), 'wb+').write(res_data)
_logger.debug("Have a %s report for %s, will examine it", res_format, rname)
if res_format == 'pdf':
@@ -128,7 +130,7 @@ def try_report_action(cr, uid, action_id, active_model=None, active_ids=None,
action = env.ref(action_id)
act_model, act_id = action._name, action.id
else:
- assert isinstance(action_id, (long, int))
+ assert isinstance(action_id, pycompat.integer_types)
act_model = 'ir.action.act_window' # assume that
act_id = action_id
act_xmlid = '<%s>' % act_id
diff --git a/odoo/tools/translate.py b/odoo/tools/translate.py
index 16a7bd9015e..75495b4bbae 100644
--- a/odoo/tools/translate.py
+++ b/odoo/tools/translate.py
@@ -20,7 +20,7 @@ from babel.messages import extract
from lxml import etree
import odoo
-from odoo.tools import config
+from odoo.tools import config, pycompat
from odoo.tools.misc import file_open, get_iso_codes, SKIPPED_ELEMENT_TYPES
from odoo.tools.osutil import walksymlinks
from odoo import sql_db, SUPERUSER_ID
@@ -679,7 +679,7 @@ def trans_export(lang, modules, buffer, format, cr):
tmpmoddir = join(tmpdir, mod, 'i18n')
os.makedirs(tmpmoddir)
pofilename = (lang if lang else mod) + ".po" + ('t' if not lang else '')
- buf = file(join(tmpmoddir, pofilename), 'w')
+ buf = open(join(tmpmoddir, pofilename), 'w')
_process('po', [mod], modrows, buf, lang)
buf.close()
@@ -1106,7 +1106,7 @@ def trans_load_data(cr, fileobj, fileformat, lang, lang_name=None, verbose=True,
if not res_id:
return
- if isinstance(res_id, (int, long)) or \
+ if isinstance(res_id, pycompat.integer_types) or \
(isinstance(res_id, basestring) and res_id.isdigit()):
dic['res_id'] = int(res_id)
if module_name: