summaryrefslogtreecommitdiff
path: root/odoo/addons
diff options
context:
space:
mode:
authorxmo-odoo <xmo@odoo.com>2017-05-10 09:39:55 +0200
committerGitHub <noreply@github.com>2017-05-10 09:39:55 +0200
commitfffaf735f58f1ac57781c095eb552de6d1fcdc47 (patch)
tree88ab0ab65430d871862a836524e0ecc890d1674d /odoo/addons
parent10eee18a047d35305dc46282e610e88936d81ffc (diff)
[FIX] P3: list -> iterable builtins (#16811)
In Python 3: * various builtins and dict methods were changed to return view/iterable objects rather than lists * and the separate Python 2 view/iterable builtins and methods were removed altogether This is problematic when using these items as list (which the happens repeatedly in Odoo), but more viciously when iterating *multiple times* over them (which also happens, which I've messed up multiple times while writing this, and which is a pain to debug even when you've just created the issue). Convert all code using these to semantics-matching cross-version helper functions to get the LCD behaviour between P2 and P3, and forbid the builtins via lint. issue #8530
Diffstat (limited to 'odoo/addons')
-rw-r--r--odoo/addons/base/ir/ir_actions.py25
-rw-r--r--odoo/addons/base/ir/ir_attachment.py10
-rw-r--r--odoo/addons/base/ir/ir_config_parameter.py4
-rw-r--r--odoo/addons/base/ir/ir_fields.py16
-rw-r--r--odoo/addons/base/ir/ir_http.py5
-rw-r--r--odoo/addons/base/ir/ir_mail_server.py17
-rw-r--r--odoo/addons/base/ir/ir_model.py30
-rw-r--r--odoo/addons/base/ir/ir_qweb/assetsbundle.py8
-rw-r--r--odoo/addons/base/ir/ir_qweb/ir_qweb.py8
-rw-r--r--odoo/addons/base/ir/ir_qweb/qweb.py55
-rw-r--r--odoo/addons/base/ir/ir_sequence.py3
-rw-r--r--odoo/addons/base/ir/ir_translation.py6
-rw-r--r--odoo/addons/base/ir/ir_ui_view.py38
-rw-r--r--odoo/addons/base/ir/ir_values.py6
-rw-r--r--odoo/addons/base/module/module.py16
-rw-r--r--odoo/addons/base/module/report/ir_module_reference_print.py4
-rw-r--r--odoo/addons/base/res/ir_property.py8
-rw-r--r--odoo/addons/base/res/res_company.py3
-rw-r--r--odoo/addons/base/res/res_config.py14
-rw-r--r--odoo/addons/base/res/res_lang.py7
-rw-r--r--odoo/addons/base/res/res_partner.py2
-rw-r--r--odoo/addons/base/res/res_users.py34
-rw-r--r--odoo/addons/base/tests/test_api.py8
-rw-r--r--odoo/addons/base/tests/test_expression.py6
-rw-r--r--odoo/addons/base/tests/test_float.py6
-rw-r--r--odoo/addons/base/tests/test_ir_filters.py27
-rw-r--r--odoo/addons/base/tests/test_orm.py8
-rw-r--r--odoo/addons/base/tests/test_qweb.py3
-rw-r--r--odoo/addons/base/tests/test_search.py5
-rw-r--r--odoo/addons/base/tests/test_views.py2
-rw-r--r--odoo/addons/test_impex/tests/test_export.py5
-rw-r--r--odoo/addons/test_limits/models.py3
-rw-r--r--odoo/addons/test_new_api/models.py5
-rw-r--r--odoo/addons/test_new_api/tests/test_one2many.py2
-rw-r--r--odoo/addons/test_pylint/tests/test_pylint.py39
35 files changed, 243 insertions, 195 deletions
diff --git a/odoo/addons/base/ir/ir_actions.py b/odoo/addons/base/ir/ir_actions.py
index 918e5d90880..4979c898e08 100644
--- a/odoo/addons/base/ir/ir_actions.py
+++ b/odoo/addons/base/ir/ir_actions.py
@@ -5,6 +5,7 @@ import odoo
from odoo import api, fields, models, tools, SUPERUSER_ID, _
from odoo.exceptions import MissingError, UserError, ValidationError, AccessError
from odoo.tools.safe_eval import safe_eval, test_python_expr
+from odoo.tools import pycompat
from odoo.http import request
import datetime
@@ -649,17 +650,19 @@ class IrActionsTodo(models.Model):
"""
user_groups = self.env.user.groups_id
- def groups_match(todo):
- """ Checks if the todo's groups match those of the current user """
- return not todo.groups_id or bool(todo.groups_id & user_groups)
-
- done = filter(groups_match, self.browse(self.search([('state', '!=', 'open')])))
- total = filter(groups_match, self.browse(self.search([])))
-
+ done_count = self.search_count([
+ ('state', '!=', open),
+ '|', ('groups_id', '=', False),
+ ('groups_id', 'in', user_groups.ids),
+ ])
+ total_count = self.search_count([
+ '|', ('groups_id', '=', False),
+ ('groups_id', 'in', user_groups.ids),
+ ])
return {
- 'done': len(done),
- 'total': len(total),
- 'todo': len(total) - len(done),
+ 'done': done_count,
+ 'total': total_count,
+ 'todo': total_count - done_count,
}
@@ -688,7 +691,7 @@ class IrActionsActClient(models.Model):
@api.depends('params_store')
def _compute_params(self):
self_bin = self.with_context(bin_size=False, bin_size_params_store=False)
- for record, record_bin in zip(self, self_bin):
+ for record, record_bin in pycompat.izip(self, self_bin):
record.params = record_bin.params_store and safe_eval(record_bin.params_store, {'uid': self._uid})
def _inverse_params(self):
diff --git a/odoo/addons/base/ir/ir_attachment.py b/odoo/addons/base/ir/ir_attachment.py
index b6bd9a08ee7..9d19d076438 100644
--- a/odoo/addons/base/ir/ir_attachment.py
+++ b/odoo/addons/base/ir/ir_attachment.py
@@ -11,7 +11,7 @@ from collections import defaultdict
from odoo import api, fields, models, tools, SUPERUSER_ID, _
from odoo.exceptions import AccessError
-from odoo.tools import config, human_size, ustr, html_escape
+from odoo.tools import config, human_size, ustr, html_escape, pycompat
from odoo.tools.mimetypes import guess_mimetype
_logger = logging.getLogger(__name__)
@@ -167,7 +167,7 @@ class IrAttachment(models.Model):
# remove garbage files, and clean up checklist
removed = 0
- for fname, filepath in checklist.iteritems():
+ for fname, filepath in pycompat.items(checklist):
if fname not in whitelist:
try:
os.unlink(self._full_path(fname))
@@ -318,7 +318,7 @@ class IrAttachment(models.Model):
model_ids[values['res_model']].add(values['res_id'])
# check access rights on the records
- for res_model, res_ids in model_ids.iteritems():
+ for res_model, res_ids in pycompat.items(model_ids):
# ignore attachments that are not attached to a resource anymore
# when checking access rights (resource was deleted but attachment
# was not)
@@ -374,12 +374,12 @@ class IrAttachment(models.Model):
# To avoid multiple queries for each attachment found, checks are
# performed in batch as much as possible.
- for res_model, targets in model_attachments.iteritems():
+ for res_model, targets in pycompat.items(model_attachments):
if res_model not in self.env:
continue
if not self.env[res_model].check_access_rights('read', False):
# remove all corresponding attachment ids
- ids.difference_update(itertools.chain(*targets.itervalues()))
+ ids.difference_update(itertools.chain(*pycompat.values(targets)))
continue
# filter ids according to what access rules permit
target_ids = list(targets)
diff --git a/odoo/addons/base/ir/ir_config_parameter.py b/odoo/addons/base/ir/ir_config_parameter.py
index cbb44ca6457..8e4ea20b5a5 100644
--- a/odoo/addons/base/ir/ir_config_parameter.py
+++ b/odoo/addons/base/ir/ir_config_parameter.py
@@ -8,7 +8,7 @@ import uuid
import logging
from odoo import api, fields, models
-from odoo.tools import config, ormcache, mute_logger
+from odoo.tools import config, ormcache, mute_logger, pycompat
_logger = logging.getLogger(__name__)
@@ -42,7 +42,7 @@ class IrConfigParameter(models.Model):
Initializes the parameters listed in _default_parameters.
It overrides existing parameters if force is ``True``.
"""
- for key, func in _default_parameters.iteritems():
+ for key, func in pycompat.items(_default_parameters):
# force=True skips search and always performs the 'if' body (because ids=False)
params = self.sudo().search([('key', '=', key)])
if force or not params:
diff --git a/odoo/addons/base/ir/ir_fields.py b/odoo/addons/base/ir/ir_fields.py
index 26c351d6fa8..204d4599425 100644
--- a/odoo/addons/base/ir/ir_fields.py
+++ b/odoo/addons/base/ir/ir_fields.py
@@ -8,13 +8,13 @@ import psycopg2
import pytz
from odoo import api, fields, models, _
-from odoo.tools import ustr
+from odoo.tools import ustr, pycompat
REFERENCING_FIELDS = {None, 'id', '.id'}
def only_ref_fields(record):
- return {k: v for k, v in record.iteritems() if k in REFERENCING_FIELDS}
+ return {k: v for k, v in pycompat.items(record) if k in REFERENCING_FIELDS}
def exclude_ref_fields(record):
- return {k: v for k, v in record.iteritems() if k not in REFERENCING_FIELDS}
+ return {k: v for k, v in pycompat.items(record) if k not in REFERENCING_FIELDS}
CREATE = lambda values: (0, False, values)
UPDATE = lambda id, values: (1, id, values)
@@ -43,9 +43,9 @@ class IrFieldsConverter(models.AbstractModel):
if isinstance(error_params, basestring):
error_params = sanitize(error_params)
elif isinstance(error_params, dict):
- error_params = {k: sanitize(v) for k, v in error_params.iteritems()}
+ error_params = {k: sanitize(v) for k, v in pycompat.items(error_params)}
elif isinstance(error_params, tuple):
- error_params = tuple(map(sanitize, error_params))
+ error_params = tuple(sanitize(v) for v in error_params)
return error_type(error_msg % error_params, error_args)
@api.model
@@ -64,12 +64,12 @@ class IrFieldsConverter(models.AbstractModel):
converters = {
name: self.to_field(model, field, fromtype)
- for name, field in model._fields.iteritems()
+ for name, field in pycompat.items(model._fields)
}
def fn(record, log):
converted = {}
- for field, value in record.iteritems():
+ for field, value in pycompat.items(record):
if field in REFERENCING_FIELDS:
continue
if not value:
@@ -369,7 +369,7 @@ class IrFieldsConverter(models.AbstractModel):
:rtype: str, list
"""
# Can import by name_get, external id or database id
- fieldset = set(record.iterkeys())
+ fieldset = set(record)
if fieldset - REFERENCING_FIELDS:
raise ValueError(
_(u"Can not create Many-To-One records indirectly, import the field separately"))
diff --git a/odoo/addons/base/ir/ir_http.py b/odoo/addons/base/ir/ir_http.py
index 3d9c72aec60..aa23531055e 100644
--- a/odoo/addons/base/ir/ir_http.py
+++ b/odoo/addons/base/ir/ir_http.py
@@ -21,6 +21,7 @@ import odoo
from odoo import api, http, models, tools, SUPERUSER_ID
from odoo.exceptions import AccessDenied, AccessError
from odoo.http import request, STATIC_CACHE, content_disposition
+from odoo.tools import pycompat
from odoo.tools.mimetypes import guess_mimetype
from odoo.modules.module import get_resource_path, get_module_path
@@ -54,7 +55,7 @@ class ModelsConverter(werkzeug.routing.BaseConverter):
def to_python(self, value):
env = api.Environment(request.cr, UID_PLACEHOLDER, request.context)
- return env[self.model].browse(map(int, value.split(',')))
+ return env[self.model].browse(int(v) for v in value.split(','))
def to_url(self, value):
return ",".join(value.ids)
@@ -202,7 +203,7 @@ class IrHttp(models.AbstractModel):
@classmethod
def _postprocess_args(cls, arguments, rule):
""" post process arg to set uid on browse records """
- for name, arg in arguments.items():
+ for name, arg in list(pycompat.items(arguments)):
if isinstance(arg, models.BaseModel) and arg._uid is UID_PLACEHOLDER:
arguments[name] = arg.sudo(request.uid)
if not arg.exists():
diff --git a/odoo/addons/base/ir/ir_mail_server.py b/odoo/addons/base/ir/ir_mail_server.py
index 22f78da6c18..737e9806d68 100644
--- a/odoo/addons/base/ir/ir_mail_server.py
+++ b/odoo/addons/base/ir/ir_mail_server.py
@@ -13,9 +13,11 @@ import re
import smtplib
import threading
+import itertools
+
from odoo import api, fields, models, tools, _
from odoo.exceptions import except_orm, UserError
-from odoo.tools import html2text, ustr
+from odoo.tools import html2text, ustr, pycompat
_logger = logging.getLogger(__name__)
_test_logger = logging.getLogger('odoo.tests')
@@ -110,7 +112,7 @@ def extract_rfc2822_addresses(text):
if not text:
return []
candidates = address_pattern.findall(ustr(text).encode('utf-8'))
- return filter(try_coerce_ascii, candidates)
+ return [c for c in candidates if try_coerce_ascii(c)]
def encode_rfc2822_address_header(header_text):
@@ -127,7 +129,7 @@ def encode_rfc2822_address_header(header_text):
return formataddr((name, email))
addresses = getaddresses([ustr(header_text).encode('utf-8')])
- return COMMASPACE.join(map(encode_addr, addresses))
+ return COMMASPACE.join(encode_addr(a) for a in addresses)
class IrMailServer(models.Model):
@@ -333,7 +335,7 @@ class IrMailServer(models.Model):
msg['Bcc'] = encode_rfc2822_address_header(COMMASPACE.join(email_bcc))
msg['Date'] = formatdate()
# Custom headers may override normal headers or provide additional ones
- for key, value in headers.iteritems():
+ for key, value in pycompat.items(headers):
msg[ustr(key).encode('utf-8')] = encode_header(value)
if subtype == 'html' and not body_alternative and html2text:
@@ -442,7 +444,12 @@ class IrMailServer(models.Model):
email_cc = message['Cc']
email_bcc = message['Bcc']
- smtp_to_list = filter(None, tools.flatten(map(extract_rfc2822_addresses, [email_to, email_cc, email_bcc])))
+ smtp_to_list = [
+ address
+ for base in [email_to, email_cc, email_bcc]
+ for address in extract_rfc2822_addresses(base)
+ if address
+ ]
assert smtp_to_list, self.NO_VALID_RECIPIENT
x_forge_to = message['X-Forge-To']
diff --git a/odoo/addons/base/ir/ir_model.py b/odoo/addons/base/ir/ir_model.py
index ad72694d410..9272a790fbc 100644
--- a/odoo/addons/base/ir/ir_model.py
+++ b/odoo/addons/base/ir/ir_model.py
@@ -45,7 +45,7 @@ def query_insert(cr, table, values):
query = INSERT_QUERY.format(
table=table,
cols=",".join(values),
- vals=",".join(map("%({0})s".format, values)),
+ vals=",".join("%({0})s".format(v) for v in values),
)
cr.execute(query, values)
@@ -53,8 +53,8 @@ def query_update(cr, table, values, selectors):
setters = set(values) - set(selectors)
query = UPDATE_QUERY.format(
table=table,
- assignment=",".join(map("{0}=%({0})s".format, setters)),
- condition=" AND ".join(map("{0}=%({0})s".format, selectors)),
+ assignment=",".join("{0}=%({0})s".format(s) for s in setters),
+ condition=" AND ".join("{0}=%({0})s".format(s) for s in selectors),
)
cr.execute(query, values)
@@ -188,7 +188,7 @@ class IrModel(models.Model):
@api.multi
def write(self, vals):
if '__last_update' in self._context:
- self = self.with_context({k: v for k, v in self._context.iteritems() if k != '__last_update'})
+ self = self.with_context({k: v for k, v in pycompat.items(self._context) if k != '__last_update'})
if 'model' in vals and any(rec.model != vals['model'] for rec in self):
raise UserError(_('Field "Model" cannot be modified on models.'))
if 'state' in vals and any(rec.state != vals['state'] for rec in self):
@@ -559,8 +559,8 @@ class IrModelFields(models.Model):
except Exception:
raise UserError("\n".join([
_("Cannot rename/delete fields that are still present in views:"),
- _("Fields:") + " " + ", ".join(map(str, fields)),
- _("View:") + " " + view.name,
+ _("Fields: %s") % ", ".join(str(f) for f in fields),
+ _("View: %s") % view.name,
]))
finally:
# the registry has been modified, restore it
@@ -760,7 +760,7 @@ class IrModelFields(models.Model):
fields_data[field.name] = dict(params, id=record.id)
return record
- diff = {key for key, val in params.items() if field_data[key] != val}
+ diff = {key for key, val in pycompat.items(params) if field_data[key] != val}
if diff:
cr = self.env.cr
# update the entry in this table
@@ -778,7 +778,7 @@ class IrModelFields(models.Model):
def _reflect_model(self, model):
""" Reflect the given model's fields. """
self.clear_caches()
- for field in model._fields.itervalues():
+ for field in pycompat.values(model._fields):
self._reflect_field(field)
if not self.pool._init:
@@ -1228,7 +1228,7 @@ class IrModelData(models.Model):
@api.depends('module', 'name')
def _compute_complete_name(self):
for res in self:
- res.complete_name = ".".join(filter(None, [res.module, res.name]))
+ res.complete_name = ".".join(n for n in [res.module, res.name] if n)
@api.depends('model', 'res_id')
def _compute_reference(self):
@@ -1259,7 +1259,7 @@ class IrModelData(models.Model):
model_id_name[xid.model][xid.res_id] = None
# fill in model_id_name with name_get() of corresponding records
- for model, id_name in model_id_name.iteritems():
+ for model, id_name in pycompat.items(model_id_name):
try:
ng = self.env[model].browse(id_name).name_get()
id_name.update(ng)
@@ -1356,7 +1356,7 @@ class IrModelData(models.Model):
record = self.get_object(module, xml_id)
if record:
self.loads[(module, xml_id)] = (model, record.id)
- for parent_model, parent_field in self.env[model]._inherits.iteritems():
+ for parent_model, parent_field in pycompat.items(self.env[model]._inherits):
parent = record[parent_field]
parent_xid = '%s_%s' % (xml_id, parent_model.replace('.', '_'))
self.loads[(module, parent_xid)] = (parent_model, parent.id)
@@ -1411,7 +1411,7 @@ class IrModelData(models.Model):
elif record:
record.write(values)
if xml_id:
- for parent_model, parent_field in record._inherits.iteritems():
+ for parent_model, parent_field in pycompat.items(record._inherits):
self.sudo().create({
'name': xml_id + '_' + parent_model.replace('.', '_'),
'model': parent_model,
@@ -1430,7 +1430,7 @@ class IrModelData(models.Model):
elif mode == 'init' or (mode == 'update' and xml_id):
existing_parents = set() # {parent_model, ...}
if xml_id:
- for parent_model, parent_field in record._inherits.iteritems():
+ for parent_model, parent_field in pycompat.items(record._inherits):
xid = self.sudo().search([
('module', '=', module),
('name', '=', xml_id + '_' + parent_model.replace('.', '_')),
@@ -1450,7 +1450,7 @@ class IrModelData(models.Model):
inherit_models = [record]
while inherit_models:
current_model = inherit_models.pop()
- for parent_model_name, parent_field in current_model._inherits.iteritems():
+ for parent_model_name, parent_field in pycompat.items(current_model._inherits):
inherit_models.append(self.env[parent_model_name])
if parent_model_name in existing_parents:
continue
@@ -1476,7 +1476,7 @@ class IrModelData(models.Model):
if xml_id and record:
self.loads[(module, xml_id)] = (model, record.id)
- for parent_model, parent_field in record._inherits.iteritems():
+ for parent_model, parent_field in pycompat.items(record._inherits):
parent_xml_id = xml_id + '_' + parent_model.replace('.', '_')
self.loads[(module, parent_xml_id)] = (parent_model, record[parent_field].id)
diff --git a/odoo/addons/base/ir/ir_qweb/assetsbundle.py b/odoo/addons/base/ir/ir_qweb/assetsbundle.py
index 5bc2dec8a9b..19902e78d1b 100644
--- a/odoo/addons/base/ir/ir_qweb/assetsbundle.py
+++ b/odoo/addons/base/ir/ir_qweb/assetsbundle.py
@@ -13,7 +13,7 @@ from odoo.http import request
from odoo.modules.module import get_resource_path
import psycopg2
import werkzeug
-from odoo.tools import func, misc
+from odoo.tools import func, misc, pycompat
import logging
_logger = logging.getLogger(__name__)
@@ -308,7 +308,7 @@ class AssetsBundle(object):
outdated = False
assets = dict((asset.html_url, asset) for asset in self.stylesheets if isinstance(asset, atype))
if assets:
- assets_domain = [('url', 'in', assets.keys())]
+ assets_domain = [('url', 'in', list(assets))]
attachments = self.env['ir.attachment'].sudo().search(assets_domain)
for attachment in attachments:
asset = assets[attachment.url]
@@ -320,7 +320,7 @@ class AssetsBundle(object):
if not asset._content and attachment.file_size > 0:
asset._content = None # file missing, force recompile
- if any(asset._content is None for asset in assets.itervalues()):
+ if any(asset._content is None for asset in pycompat.values(assets)):
outdated = True
if outdated:
@@ -452,7 +452,7 @@ class WebAsset(object):
def stat(self):
if not (self.inline or self._filename or self._ir_attach):
- path = filter(None, self.url.split('/'))
+ path = (segment for segment in self.url.split('/') if segment)
self._filename = get_resource_path(*path)
if self._filename:
return
diff --git a/odoo/addons/base/ir/ir_qweb/ir_qweb.py b/odoo/addons/base/ir/ir_qweb/ir_qweb.py
index 68c4bf048d7..5548fcd47d8 100644
--- a/odoo/addons/base/ir/ir_qweb/ir_qweb.py
+++ b/odoo/addons/base/ir/ir_qweb/ir_qweb.py
@@ -75,7 +75,7 @@ class IrQWeb(models.AbstractModel, QWeb):
# apply ormcache_context decorator unless in dev mode...
@tools.conditional(
'xml' not in tools.config['dev_mode'],
- tools.ormcache('id_or_xml_id', 'tuple(map(options.get, self._get_template_cache_keys()))'),
+ tools.ormcache('id_or_xml_id', 'tuple(options.get(k) for k in self._get_template_cache_keys())'),
)
def compile(self, id_or_xml_id, options):
return super(IrQWeb, self).compile(id_or_xml_id, options=options)
@@ -173,7 +173,7 @@ class IrQWeb(models.AbstractModel, QWeb):
if field_options and 'monetary' in field_options:
try:
options = "{'widget': 'monetary'"
- for k, v in json.loads(field_options).iteritems():
+ for k, v in pycompat.items(json.loads(field_options)):
if k in ('display_currency', 'from_currency'):
options = "%s, '%s': %s" % (options, k, v)
else:
@@ -238,12 +238,12 @@ class IrQWeb(models.AbstractModel, QWeb):
atype = 'text/less'
if atype not in ('text/less', 'text/sass'):
atype = 'text/css'
- path = filter(None, href.split('/'))
+ path = [segment for segment in href.split('/') if segment]
filename = get_resource_path(*path) if path else None
files.append({'atype': atype, 'url': href, 'filename': filename, 'content': el.text, 'media': media})
elif el.tag == 'script':
atype = 'text/javascript'
- path = filter(None, src.split('/'))
+ path = [segment for segment in src.split('/') if segment]
filename = get_resource_path(*path) if path else None
files.append({'atype': atype, 'url': src, 'filename': filename, 'content': el.text, 'media': media})
else:
diff --git a/odoo/addons/base/ir/ir_qweb/qweb.py b/odoo/addons/base/ir/ir_qweb/qweb.py
index 14a0a54fbd9..06aba8ccdb4 100644
--- a/odoo/addons/base/ir/ir_qweb/qweb.py
+++ b/odoo/addons/base/ir/ir_qweb/qweb.py
@@ -6,14 +6,15 @@ import traceback
from collections import OrderedDict, Sized, Mapping, defaultdict
from functools import reduce
-from itertools import chain, izip, tee, count
+from itertools import tee, count
from textwrap import dedent
+import itertools
from lxml import etree, html
import werkzeug
from werkzeug.utils import escape as _escape
-from odoo.tools import pycompat
+from odoo.tools import pycompat, freehash
try:
import builtins
@@ -82,7 +83,7 @@ class Contextifier(ast.NodeTransformer):
return ast.copy_location(ast.Lambda(
args=ast.arguments(
args=args.args,
- defaults=map(self.visit, args.defaults),
+ defaults=[self.visit(default) for default in args.defaults],
vararg=args.vararg,
kwarg=args.kwarg,
),
@@ -109,7 +110,7 @@ class Contextifier(ast.NodeTransformer):
for field, value in ast.iter_fields(node):
# map transformation of comprehensions
if isinstance(value, list):
- setattr(newnode, field, map(transformer.visit, value))
+ setattr(newnode, field, [transformer.visit(v) for v in value])
else: # set transformation of key/value/expr fields
setattr(newnode, field, transformer.visit(value))
return newnode
@@ -168,14 +169,14 @@ def foreach_iterator(base_ctx, enum, name):
if not enum:
return
if isinstance(enum, int):
- enum = pycompat.range(enum)
+ enum = range(enum)
size = None
if isinstance(enum, Sized):
ctx["%s_size" % name] = size = len(enum)
if isinstance(enum, Mapping):
- enum = enum.iteritems()
+ enum = pycompat.items(enum)
else:
- enum = izip(*tee(enum))
+ enum = pycompat.izip(*tee(enum))
value_key = '%s_value' % name
index_key = '%s_index' % name
first_key = '%s_first' % name
@@ -201,7 +202,7 @@ def foreach_iterator(base_ctx, enum, name):
yield ctx
# copy changed items back into source context (?)
# FIXME: maybe values could provide a ChainMap-style clone?
- for k in base_ctx.keys():
+ for k in list(base_ctx):
base_ctx[k] = ctx[k]
_FORMAT_REGEX = re.compile(
@@ -226,7 +227,7 @@ class frozendict(dict):
def update(self, *args, **kwargs):
raise NotImplementedError("'update' not supported on frozendict")
def __hash__(self):
- return hash(frozenset((key, freehash(val)) for key, val in self.iteritems()))
+ return hash(frozenset((key, freehash(val)) for key, val in pycompat.items(self)))
####################################
@@ -510,6 +511,7 @@ class QWeb(object):
"""
return ast.parse(dedent("""
from collections import OrderedDict
+ from odoo.tools import pycompat
from odoo.addons.base.ir.ir_qweb.qweb import escape, unicodifier, foreach_iterator
"""))
@@ -665,7 +667,7 @@ class QWeb(object):
# all directives have been compiled, there should be none left
if any(att.startswith('t-') for att in el.attrib):
- raise "Unknown directive on %s" % ("', '".join(directives), etree.tostring(el))
+ raise NameError("Unknown directive on %s" % etree.tostring(el))
return []
def _values_var(self, varname, ctx):
@@ -726,7 +728,7 @@ class QWeb(object):
attrib = {}
# If `el` introduced new namespaces, write them as attribute by using the
# `attrib` dict.
- for ns_prefix, ns_definition in set(el.nsmap.items()) - set(options['nsmap'].items()):
+ for ns_prefix, ns_definition in set(pycompat.items(el.nsmap)) - set(pycompat.items(options['nsmap'])):
if ns_prefix is None:
attrib['xmlns'] = ns_definition
else:
@@ -735,8 +737,9 @@ class QWeb(object):
# Etree will also remove the ns prefixes indirection in the attributes. As we only have
# the namespace definition, we'll use an nsmap where the keys are the definitions and
# the values the prefixes in order to get back the right prefix and restore it.
- nsprefixmap = {v: k for k, v in options['nsmap'].items() + el.nsmap.items()}
- for key, value in el.attrib.items():
+ ns = itertools.chain(pycompat.items(options['nsmap']), pycompat.items(el.nsmap))
+ nsprefixmap = {v: k for k, v in ns}
+ for key, value in pycompat.items(el.attrib):
attrib_qname = etree.QName(key)
if attrib_qname.namespace:
attrib['%s:%s' % (nsprefixmap[attrib_qname.namespace], attrib_qname.localname)] = value
@@ -754,7 +757,7 @@ class QWeb(object):
if unqualified_el_tag == 't':
return content
- tag = u'<%s%s' % (el_tag, u''.join([u' %s="%s"' % (name, escape(unicodifier(value))) for name, value in attrib.iteritems()]))
+ tag = u'<%s%s' % (el_tag, u''.join([u' %s="%s"' % (name, escape(unicodifier(value))) for name, value in pycompat.items(attrib)]))
if unqualified_el_tag in self._void_elements:
return [self._append(ast.Str(tag + '/>'))] + content
else:
@@ -766,10 +769,10 @@ class QWeb(object):
# Etree will also remove the ns prefixes indirection in the attributes. As we only have
# the namespace definition, we'll use an nsmap where the keys are the definitions and
# the values the prefixes in order to get back the right prefix and restore it.
- nsprefixmap = {v: k for k, v in options['nsmap'].items() + el.nsmap.items()}
+ nsprefixmap = {v: k for k, v in itertools.chain(pycompat.items(options['nsmap']), pycompat.items(el.nsmap))}
nodes = []
- for key, value in el.attrib.iteritems():
+ for key, value in pycompat.items(el.attrib):
if not key.startswith('t-'):
attrib_qname = etree.QName(key)
if attrib_qname.namespace:
@@ -784,7 +787,7 @@ class QWeb(object):
We do not support namespaced dynamic attributes.
"""
nodes = []
- for name, value in el.attrib.iteritems():
+ for name, value in pycompat.items(el.attrib):
if name.startswith('t-attf-'):
nodes.append((name[7:], self._compile_format(value)))
elif name.startswith('t-att-'):
@@ -810,7 +813,7 @@ class QWeb(object):
def _compile_all_attributes(self, el, options, attr_already_created=False):
""" Compile the attributes of the given elements into a list of AST nodes. """
body = []
- if any(name.startswith('t-att') or not name.startswith('t-') for name, value in el.attrib.iteritems()):
+ if any(name.startswith('t-att') or not name.startswith('t-') for name, value in pycompat.items(el.attrib)):
if not attr_already_created:
attr_already_created = True
body.append(
@@ -851,7 +854,7 @@ class QWeb(object):
)))
if attr_already_created:
- # for name, value in t_attrs.iteritems():
+ # for name, value in pycompat.items(t_attrs):
# if value or isinstance(value, basestring)):
# append(u' ')
# append(name)
@@ -862,11 +865,11 @@ class QWeb(object):
target=ast.Tuple(elts=[ast.Name(id='name', ctx=ast.Store()), ast.Name(id='value', ctx=ast.Store())], ctx=ast.Store()),
iter=ast.Call(
func=ast.Attribute(
- value=ast.Name(id='t_attrs', ctx=ast.Load()),
- attr='iteritems',
+ value=ast.Name(id='pycompat', ctx=ast.Load()),
+ attr='items',
ctx=ast.Load()
),
- args=[], keywords=[],
+ args=[ast.Name(id='t_attrs', ctx=ast.Load())], keywords=[],
starargs=None, kwargs=None
),
body=[ast.If(
@@ -923,7 +926,7 @@ class QWeb(object):
# If `el` introduced new namespaces, write them as attribute by using the
# `extra_attrib` dict.
- for ns_prefix, ns_definition in set(el.nsmap.items()) - set(options['nsmap'].items()):
+ for ns_prefix, ns_definition in set(pycompat.items(el.nsmap)) - set(pycompat.items(options['nsmap'])):
if ns_prefix is None:
extra_attrib['xmlns'] = ns_definition
else:
@@ -932,7 +935,7 @@ class QWeb(object):
if unqualified_el_tag == 't':
return content
- body = [self._append(ast.Str(u'<%s%s' % (el_tag, u''.join([u' %s="%s"' % (name, escape(unicodifier(value))) for name, value in extra_attrib.iteritems()]))))]
+ body = [self._append(ast.Str(u'<%s%s' % (el_tag, u''.join([u' %s="%s"' % (name, escape(unicodifier(value))) for name, value in pycompat.items(extra_attrib)]))))]
body.extend(self._compile_all_attributes(el, options, attr_already_created))
if unqualified_el_tag in self._void_elements:
body.append(self._append(ast.Str(u'/>')))
@@ -1054,7 +1057,7 @@ class QWeb(object):
def _compile_directive_if(self, el, options):
orelse = []
next_el = el.getnext()
- if next_el is not None and {'t-else', 't-elif'} & set(next_el.attrib.keys()):
+ if next_el is not None and {'t-else', 't-elif'} & set(next_el.attrib):
if el.tail and not el.tail.isspace():
raise ValueError("Unexpected non-whitespace characters between t-if and t-else directives")
el.tail = None
@@ -1437,7 +1440,7 @@ class QWeb(object):
# make the nsmap an ast dict
keys = []
values = []
- for key, value in options['nsmap'].items():
+ for key, value in pycompat.items(options['nsmap']):
if isinstance(key, basestring):
keys.append(ast.Str(s=key))
elif key is None:
diff --git a/odoo/addons/base/ir/ir_sequence.py b/odoo/addons/base/ir/ir_sequence.py
index a46f5e95eca..58961e921ba 100644
--- a/odoo/addons/base/ir/ir_sequence.py
+++ b/odoo/addons/base/ir/ir_sequence.py
@@ -6,6 +6,7 @@ import pytz
from odoo import api, fields, models, _
from odoo.exceptions import UserError
+from odoo.tools import pycompat
_logger = logging.getLogger(__name__)
@@ -178,7 +179,7 @@ class IrSequence(models.Model):
'weekday': '%w', 'h24': '%H', 'h12': '%I', 'min': '%M', 'sec': '%S'
}
res = {}
- for key, format in sequences.iteritems():
+ for key, format in pycompat.items(sequences):
res[key] = effective_date.strftime(format)
res['range_' + key] = range_date.strftime(format)
res['current_' + key] = now.strftime(format)
diff --git a/odoo/addons/base/ir/ir_translation.py b/odoo/addons/base/ir/ir_translation.py
index 7d73f40d65b..219ebcc471d 100644
--- a/odoo/addons/base/ir/ir_translation.py
+++ b/odoo/addons/base/ir/ir_translation.py
@@ -128,7 +128,7 @@ class IrTranslationImport(object):
env = api.Environment(cr, SUPERUSER_ID, {})
src_relevant_fields = []
for model in env:
- for field_name, field in env[model]._fields.items():
+ for field_name, field in pycompat.items(env[model]._fields):
if hasattr(field, 'translate') and callable(field.translate):
src_relevant_fields.append("%s,%s" % (model, field_name))
@@ -530,7 +530,7 @@ class IrTranslation(models.Model):
# check for read/write access on translated field records
fmode = 'read' if mode == 'read' else 'write'
- for mname, ids in model_ids.iteritems():
+ for mname, ids in pycompat.items(model_ids):
records = self.env[mname].browse(ids)
records.check_access_rights(fmode)
records.check_field_access_rights(fmode, model_fields[mname])
@@ -640,7 +640,7 @@ class IrTranslation(models.Model):
return ['&', ('res_id', '=', rec.id), ('name', '=', name)]
# insert missing translations, and extend domain for related fields
- for name, fld in record._fields.items():
+ for name, fld in pycompat.items(record._fields):
if not fld.translate:
continue
diff --git a/odoo/addons/base/ir/ir_ui_view.py b/odoo/addons/base/ir/ir_ui_view.py
index c557d15ee6b..0a709985ff6 100644
--- a/odoo/addons/base/ir/ir_ui_view.py
+++ b/odoo/addons/base/ir/ir_ui_view.py
@@ -8,6 +8,8 @@ import logging
import os
import re
import time
+
+import itertools
from dateutil.relativedelta import relativedelta
from operator import itemgetter
@@ -49,7 +51,7 @@ def keep_query(*keep_params, **additional_params):
if not keep_params and not additional_params:
keep_params = ('*',)
params = additional_params.copy()
- qs_keys = request.httprequest.args.keys()
+ qs_keys = list(request.httprequest.args)
for keep_param in keep_params:
for param in fnmatch.filter(qs_keys, keep_param):
if param not in additional_params and param in qs_keys:
@@ -251,11 +253,11 @@ actual arch.
@api.depends('arch')
def _compute_arch_base(self):
# 'arch_base' is the same as 'arch' without translation
- for view, view_wo_lang in zip(self, self.with_context(lang=None)):
+ for view, view_wo_lang in pycompat.izip(self, self.with_context(lang=None)):
view.arch_base = view_wo_lang.arch
def _inverse_arch_base(self):
- for view, view_wo_lang in zip(self, self.with_context(lang=None)):
+ for view, view_wo_lang in pycompat.izip(self, self.with_context(lang=None)):
view_wo_lang.arch = view.arch_base
@api.depends('write_date')
@@ -458,7 +460,7 @@ actual arch.
# not required. The root cause is the INNER JOIN
# used to implement it.
views = self.search(conditions + [('model_ids.module', 'in', tuple(self.pool._init_modules))])
- views = self.search(conditions + [('id', 'in', list(self._context.get('check_view_ids') or (0,)) + map(int, views))])
+ views = self.search(conditions + [('id', 'in', list(self._context.get('check_view_ids') or (0,)) + views.ids)])
else:
views = self.search(conditions)
@@ -581,10 +583,16 @@ actual arch.
separator = child.get('separator', ',')
if separator == ' ':
separator = None # squash spaces
- to_add = filter(bool, map(str.strip, child.get('add', '').split(separator)))
- to_remove = map(str.strip, child.get('remove', '').split(separator))
- values = map(str.strip, node.get(attribute, '').split(separator))
- value = (separator or ' ').join(filter(lambda s: s not in to_remove, values) + to_add)
+ to_add = (
+ s for s in (s.strip() for s in child.get('add', '').split(separator))
+ if s
+ )
+ to_remove = {s.strip() for s in child.get('remove', '').split(separator)}
+ values = (s.strip() for s in node.get(attribute, '').split(separator))
+ value = (separator or ' ').join(itertools.chain(
+ (v for v in values if v not in to_remove),
+ to_add
+ ))
if value:
node.set(attribute, value)
elif attribute in node.attrib:
@@ -834,7 +842,7 @@ actual arch.
collect(arch, self.env[model_name])
- for field, nodes in field_nodes.iteritems():
+ for field, nodes in pycompat.items(field_nodes):
# if field should trigger an onchange, add on_change="1" on the
# nodes referring to field
model = self.env[field.model_name]
@@ -900,7 +908,7 @@ actual arch.
node.set(action, 'false')
arch = etree.tostring(node, encoding="utf-8").replace('\t', '')
- for k in fields.keys():
+ for k in list(fields):
if k not in fields_def:
del fields[k]
for field in fields_def:
@@ -924,7 +932,7 @@ actual arch.
@tools.conditional(
'xml' not in config['dev_mode'],
tools.ormcache('frozenset(self.env.user.groups_id.ids)', 'view_id',
- 'tuple(map(self._context.get, self._read_template_keys()))'),
+ 'tuple(self._context.get(k) for k in self._read_template_keys())'),
)
def _read_template(self, view_id):
arch = self.browse(view_id).read_combined(['arch'])['arch']
@@ -1091,12 +1099,12 @@ actual arch.
Model = self.env[model]
Node = self.env[node_obj]
- for model_key, model_value in Model._fields.iteritems():
+ for model_key, model_value in pycompat.items(Model._fields):
if model_value.type == 'one2many':
if model_value.comodel_name == node_obj:
_Node_Field = model_key
_Model_Field = model_value.inverse_name
- for node_key, node_value in Node._fields.iteritems():
+ for node_key, node_value in pycompat.items(Node._fields):
if node_value.type == 'one2many':
if node_value.comodel_name == conn_obj:
# _Source_Field = "Incoming Arrows" (connected via des_node)
@@ -1159,7 +1167,7 @@ actual arch.
GROUP BY coalesce(v.inherit_id, v.id)"""
self._cr.execute(query, [model])
- rec = self.browse(map(itemgetter(0), self._cr.fetchall()))
+ rec = self.browse(it[0] for it in self._cr.fetchall())
return rec.with_context({'load_all_views': True})._check_xml()
@api.model
@@ -1173,7 +1181,7 @@ actual arch.
xmlid_filter = "AND md.name IN %s"
names = tuple(
name
- for (xmod, name), (model, res_id) in self.pool.model_data_reference_ids.items()
+ for (xmod, name), (model, res_id) in pycompat.items(self.pool.model_data_reference_ids)
if xmod == module and model == self._name
)
if not names:
diff --git a/odoo/addons/base/ir/ir_values.py b/odoo/addons/base/ir/ir_values.py
index 3672d7811c2..ace2998b2b3 100644
--- a/odoo/addons/base/ir/ir_values.py
+++ b/odoo/addons/base/ir/ir_values.py
@@ -5,7 +5,7 @@ from ast import literal_eval
from odoo import api, fields, models, tools, _
from odoo.exceptions import AccessError, MissingError, ValidationError
-from odoo.tools import pickle
+from odoo.tools import pickle, pycompat
import logging
_logger = logging.getLogger(__name__)
@@ -315,7 +315,7 @@ class IrValues(models.Model):
for row in self._cr.dictfetchall():
value = pickle.loads(row['value'].encode('utf-8'))
defaults.setdefault(row['name'], (row['id'], row['name'], value))
- return defaults.values()
+ return list(pycompat.values(defaults))
# use ormcache: this is called a lot by BaseModel.default_get()!
@api.model
@@ -426,4 +426,4 @@ class IrValues(models.Model):
results[name] = (id, name, action_def)
except (AccessError, MissingError):
continue
- return sorted(results.values())
+ return sorted(pycompat.values(results))
diff --git a/odoo/addons/base/module/module.py b/odoo/addons/base/module/module.py
index ae36ccd1727..c8a83a01bf1 100644
--- a/odoo/addons/base/module/module.py
+++ b/odoo/addons/base/module/module.py
@@ -10,6 +10,8 @@ import shutil
import tempfile
import zipfile
+from odoo.tools import pycompat
+
try:
from urllib import parse as urlparse
from urllib.request import urlopen
@@ -209,9 +211,9 @@ class Module(models.Model):
def format_view(v):
return '%s%s (%s)' % (v.inherit_id and '* INHERIT ' or '', v.name, v.type)
- module.views_by_module = "\n".join(sorted(map(format_view, browse('ir.ui.view'))))
- module.reports_by_module = "\n".join(sorted(map(attrgetter('name'), browse('ir.actions.report'))))
- module.menus_by_module = "\n".join(sorted(map(attrgetter('complete_name'), browse('ir.ui.menu'))))
+ module.views_by_module = "\n".join(sorted(format_view(v) for v in browse('ir.ui.view')))
+ module.reports_by_module = "\n".join(sorted(r.name for r in browse('ir.actions.report')))
+ module.menus_by_module = "\n".join(sorted(m.complete_name for m in browse('ir.ui.menu')))
@api.depends('icon')
def _get_icon_image(self):
@@ -668,7 +670,7 @@ class Module(models.Model):
_logger.debug('Install from url: %r', urls)
try:
# 1. Download & unzip missing modules
- for module_name, url in urls.iteritems():
+ for module_name, url in pycompat.items(urls):
if not url:
continue # nothing to download, local version is already the last one
@@ -687,7 +689,7 @@ class Module(models.Model):
assert os.path.isdir(os.path.join(tmp, module_name))
# 2a. Copy/Replace module source in addons path
- for module_name, url in urls.iteritems():
+ for module_name, url in pycompat.items(urls):
if module_name == OPENERP or not url:
continue # OPENERP is special case, handled below, and no URL means local module
module_path = modules.get_module_path(module_name, downloaded=True, display_warning=False)
@@ -719,11 +721,11 @@ class Module(models.Model):
self.update_list()
- with_urls = [module_name for module_name, url in urls.iteritems() if url]
+ with_urls = [module_name for module_name, url in pycompat.items(urls) if url]
downloaded = self.search([('name', 'in', with_urls)])
installed = self.search([('id', 'in', downloaded.ids), ('state', '=', 'installed')])
- to_install = self.search([('name', 'in', urls.keys()), ('state', '=', 'uninstalled')])
+ to_install = self.search([('name', 'in', list(urls)), ('state', '=', 'uninstalled')])
post_install_action = to_install.button_immediate_install()
if installed or to_install:
diff --git a/odoo/addons/base/module/report/ir_module_reference_print.py b/odoo/addons/base/module/report/ir_module_reference_print.py
index 1f2dff53243..a933cdd9430 100644
--- a/odoo/addons/base/module/report/ir_module_reference_print.py
+++ b/odoo/addons/base/module/report/ir_module_reference_print.py
@@ -2,6 +2,8 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, models
+from odoo.tools import pycompat
+
class IrModelReferenceReport(models.AbstractModel):
_name = 'report.base.report_irmodulereference'
@@ -21,7 +23,7 @@ class IrModelReferenceReport(models.AbstractModel):
if data:
res_ids = data.mapped('res_id')
fnames = self.env['ir.model.fields'].browse(res_ids).mapped('name')
- return sorted(self.env[model].fields_get(fnames).iteritems())
+ return sorted(pycompat.items(self.env[model].fields_get(fnames)))
return []
@api.model
diff --git a/odoo/addons/base/res/ir_property.py b/odoo/addons/base/res/ir_property.py
index 8e1b7eda860..ec086fb6c61 100644
--- a/odoo/addons/base/res/ir_property.py
+++ b/odoo/addons/base/res/ir_property.py
@@ -217,7 +217,7 @@ class Property(models.Model):
prop.write({'value': value})
# create new properties for records that do not have one yet
- for ref, id in refs.iteritems():
+ for ref, id in pycompat.items(refs):
value = clean(values[id])
if value != default_value:
self.create({
@@ -248,13 +248,13 @@ class Property(models.Model):
elif operator in ('!=', '<=', '<', '>', '>='):
value = makeref(value)
elif operator in ('in', 'not in'):
- value = map(makeref, value)
+ value = [makeref(v) for v in value]
elif operator in ('=like', '=ilike', 'like', 'not like', 'ilike', 'not ilike'):
# most probably inefficient... but correct
target = self.env[comodel]
target_names = target.name_search(value, operator=operator, limit=None)
- target_ids = map(itemgetter(0), target_names)
- operator, value = 'in', map(makeref, target_ids)
+ target_ids = [n[0] for n in target_names]
+ operator, value = 'in', [makeref(v) for v in target_ids]
elif field.type in ('integer', 'float'):
# No record is created in ir.property if the field's type is float or integer with a value
# equal to 0. Then to match with the records that are linked to a property field equal to 0,
diff --git a/odoo/addons/base/res/res_company.py b/odoo/addons/base/res/res_company.py
index 96e922f5e77..9dfdba96cba 100644
--- a/odoo/addons/base/res/res_company.py
+++ b/odoo/addons/base/res/res_company.py
@@ -6,6 +6,7 @@ import re
from odoo import api, fields, models, tools, _
from odoo.exceptions import ValidationError
+from odoo.tools import pycompat
class Company(models.Model):
@@ -146,7 +147,7 @@ class Company(models.Model):
if self.country_id:
res['domain']['state_id'] = [('country_id', '=', self.country_id.id)]
values = self.on_change_country(self.country_id.id)['value']
- for fname, value in values.iteritems():
+ for fname, value in pycompat.items(values):
setattr(self, fname, value)
return res
diff --git a/odoo/addons/base/res/res_config.py b/odoo/addons/base/res/res_config.py
index 59764fca1e8..a19c6406dcb 100644
--- a/odoo/addons/base/res/res_config.py
+++ b/odoo/addons/base/res/res_config.py
@@ -9,7 +9,7 @@ from lxml import etree
from odoo import api, models, registry, SUPERUSER_ID, _
from odoo.exceptions import AccessError, RedirectWarning, UserError
-from odoo.tools import ustr
+from odoo.tools import ustr, pycompat
_logger = logging.getLogger(__name__)
@@ -257,7 +257,7 @@ class ResConfigInstaller(models.TransientModel, ResConfigModuleInstallationMixin
installer
:rtype: [str]
"""
- return map(attrgetter('name'), self._already_installed())
+ return [m.name for m in self._already_installed()]
def _already_installed(self):
""" For each module (boolean fields in a res.config.installer),
@@ -267,7 +267,7 @@ class ResConfigInstaller(models.TransientModel, ResConfigModuleInstallationMixin
:returns: a list of all installed modules in this installer
:rtype: recordset (collection of Record)
"""
- selectable = [name for name, field in self._fields.iteritems()
+ selectable = [name for name, field in pycompat.items(self._fields)
if field.type == 'boolean']
return self.env['ir.module.module'].search([('name', 'in', selectable),
('state', 'in', ['to install', 'installed', 'to upgrade'])])
@@ -292,7 +292,7 @@ class ResConfigInstaller(models.TransientModel, ResConfigModuleInstallationMixin
"""
base = set(module_name
for installer in self.read()
- for module_name, to_install in installer.iteritems()
+ for module_name, to_install in pycompat.items(installer)
if self._fields[module_name].type == 'boolean' and to_install)
hooks_results = set()
@@ -302,7 +302,7 @@ class ResConfigInstaller(models.TransientModel, ResConfigModuleInstallationMixin
hooks_results.update(hook() or set())
additionals = set(module
- for requirements, consequences in self._install_if.iteritems()
+ for requirements, consequences in pycompat.items(self._install_if)
if base.issuperset(requirements)
for module in consequences)
@@ -462,13 +462,13 @@ class ResConfigSettings(models.TransientModel, ResConfigModuleInstallationMixin)
ref = self.env.ref
defaults, groups, modules, others = [], [], [], []
- for name, field in self._fields.iteritems():
+ for name, field in pycompat.items(self._fields):
if name.startswith('default_') and hasattr(field, 'default_model'):
defaults.append((name, field.default_model, name[8:]))
elif name.startswith('group_') and field.type in ('boolean', 'selection') and \
hasattr(field, 'implied_group'):
field_group_xmlids = getattr(field, 'group', 'base.group_user').split(',')
- field_groups = Groups.concat(*map(ref, field_group_xmlids))
+ field_groups = Groups.concat(*(ref(it) for it in field_group_xmlids))
groups.append((name, field_groups, ref(field.implied_group)))
elif name.startswith('module_') and field.type in ('boolean', 'selection'):
module = IrModule.sudo().search([('name', '=', name[7:])], limit=1)
diff --git a/odoo/addons/base/res/res_lang.py b/odoo/addons/base/res/res_lang.py
index 19a5b9be339..f4e2d7a1578 100644
--- a/odoo/addons/base/res/res_lang.py
+++ b/odoo/addons/base/res/res_lang.py
@@ -8,6 +8,7 @@ import re
from operator import itemgetter
from odoo import api, fields, models, tools, _
+from odoo.tools import pycompat
from odoo.tools.safe_eval import safe_eval
from odoo.exceptions import UserError, ValidationError
@@ -22,7 +23,7 @@ class Lang(models.Model):
_description = "Languages"
_order = "active desc,name"
- _disallowed_datetime_patterns = tools.DATETIME_FORMATS_MAP.keys()
+ _disallowed_datetime_patterns = list(tools.DATETIME_FORMATS_MAP)
_disallowed_datetime_patterns.remove('%y') # this one is in fact allowed, just not good practice
name = fields.Char(required=True)
@@ -125,7 +126,7 @@ class Lang(models.Model):
# For some locales, nl_langinfo returns a D_FMT/T_FMT that contains
# unsupported '%-' patterns, e.g. for cs_CZ
format = format.replace('%-', '%')
- for pattern, replacement in tools.DATETIME_FORMATS_MAP.iteritems():
+ for pattern, replacement in pycompat.items(tools.DATETIME_FORMATS_MAP):
format = format.replace(pattern, replacement)
return str(format)
@@ -318,5 +319,5 @@ def intersperse(string, counts, separator=''):
left, rest, right = intersperse_pat.match(string).groups()
def reverse(s): return s[::-1]
splits = split(reverse(rest), counts)
- res = separator.join(map(reverse, reverse(splits)))
+ res = separator.join(reverse(s) for s in reverse(splits))
return left + res + right, len(splits) > 0 and len(splits) -1 or 0
diff --git a/odoo/addons/base/res/res_partner.py b/odoo/addons/base/res/res_partner.py
index fe758d36de1..17e6507a01e 100644
--- a/odoo/addons/base/res/res_partner.py
+++ b/odoo/addons/base/res/res_partner.py
@@ -680,7 +680,7 @@ class Partner(models.Model):
query += ' limit %s'
where_clause_params.append(limit)
self.env.cr.execute(query, where_clause_params)
- partner_ids = map(lambda x: x[0], self.env.cr.fetchall())
+ partner_ids = [row[0] for row in self.env.cr.fetchall()]
if partner_ids:
return self.browse(partner_ids).name_get()
diff --git a/odoo/addons/base/res/res_users.py b/odoo/addons/base/res/res_users.py
index ae8863eee4d..106fc32d56f 100644
--- a/odoo/addons/base/res/res_users.py
+++ b/odoo/addons/base/res/res_users.py
@@ -2,6 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import pytz
import datetime
+import itertools
import logging
from collections import defaultdict
@@ -13,7 +14,7 @@ from odoo import api, fields, models, tools, SUPERUSER_ID, _
from odoo.exceptions import AccessDenied, AccessError, UserError, ValidationError
from odoo.osv import expression
from odoo.service.db import check_super
-from odoo.tools import partition
+from odoo.tools import partition, pycompat
_logger = logging.getLogger(__name__)
@@ -29,7 +30,7 @@ def name_boolean_group(id):
return 'in_group_' + str(id)
def name_selection_groups(ids):
- return 'sel_groups_' + '_'.join(map(str, ids))
+ return 'sel_groups_' + '_'.join(str(it) for it in ids)
def is_boolean_group(name):
return name.startswith('in_group_')
@@ -44,7 +45,7 @@ def get_boolean_group(name):
return int(name[9:])
def get_selection_groups(name):
- return map(int, name[11:].split('_'))
+ return [int(v) for v in name[11:].split('_')]
def parse_m2m(commands):
"return a list of ids corresponding to a many2many value"
@@ -92,7 +93,7 @@ class Groups(models.Model):
@api.depends('category_id.name', 'name')
def _compute_full_name(self):
# Important: value must be stored in environment of group, not group1!
- for group, group1 in zip(self, self.sudo()):
+ for group, group1 in pycompat.izip(self, self.sudo()):
if group1.category_id:
group.full_name = '%s / %s' % (group1.category_id.name, group1.name)
else:
@@ -111,7 +112,7 @@ class Groups(models.Model):
operand = [operand]
where = []
for group in operand:
- values = filter(bool, group.split('/'))
+ values = [v for v in group.split('/') if v]
group_name = values.pop().strip()
category_name = values and '/'.join(values).strip() or group_name
group_domain = [('name', operator, lst and [group_name] or group_name)]
@@ -299,13 +300,11 @@ class Users(models.Model):
canwrite = self.env['ir.model.access'].check('res.users', 'write', False)
if not canwrite:
- def override_password(vals):
- if (vals['id'] != self._uid):
+ for vals in result:
+ if vals['id'] != self._uid:
for key in USER_PRIVATE_FIELDS:
if key in vals:
vals[key] = '********'
- return vals
- result = map(override_password, result)
return result
@@ -343,7 +342,7 @@ class Users(models.Model):
raise UserError(_("You cannot deactivate the user you're currently logged in as."))
if self == self.env.user:
- for key in values.keys():
+ for key in list(values):
if not (key in self.SELF_WRITEABLE_FIELDS or key.startswith('context_')):
break
else:
@@ -624,7 +623,7 @@ class GroupsImplied(models.Model):
if values.get('users') or values.get('implied_ids'):
# add all implied groups (to all users of each group)
for group in self:
- vals = {'users': zip(repeat(4), group.with_context(active_test=False).users.ids)}
+ vals = {'users': list(pycompat.izip(repeat(4), group.with_context(active_test=False).users.ids))}
super(GroupsImplied, group.trans_implied_ids).write(vals)
return res
@@ -766,7 +765,7 @@ class GroupsView(models.Model):
# determine sequence order: a group appears after its implied groups
order = {g: len(g.trans_implied_ids & gs) for g in gs}
# check whether order is total, i.e., sequence orders are distinct
- if len(set(order.itervalues())) == len(gs):
+ if len(set(pycompat.values(order))) == len(gs):
return (app, 'selection', gs.sorted(key=order.get))
else:
return (app, 'boolean', gs)
@@ -780,7 +779,7 @@ class GroupsView(models.Model):
others += g
# build the result
res = []
- for app, gs in sorted(by_app.iteritems(), key=lambda it: it[0].sequence or 0):
+ for app, gs in sorted(pycompat.items(by_app), key=lambda it: it[0].sequence or 0):
res.append(linearize(app, gs))
if others:
res.append((self.env['ir.module.category'], 'boolean', others))
@@ -820,7 +819,7 @@ class UsersView(models.Model):
add, rem = [], []
values1 = {}
- for key, val in values.iteritems():
+ for key, val in pycompat.items(values):
if is_boolean_group(key):
(add if val else rem).append(get_boolean_group(key))
elif is_selection_groups(key):
@@ -832,7 +831,10 @@ class UsersView(models.Model):
if 'groups_id' not in values and (add or rem):
# remove group ids in `rem` and add group ids in `add`
- values1['groups_id'] = zip(repeat(3), rem) + zip(repeat(4), add)
+ values1['groups_id'] = list(itertools.chain(
+ pycompat.izip(repeat(3), rem),
+ pycompat.izip(repeat(4), add)
+ ))
return values1
@@ -847,7 +849,7 @@ class UsersView(models.Model):
@api.multi
def read(self, fields=None, load='_classic_read'):
# determine whether reified groups fields are required, and which ones
- fields1 = fields or self.fields_get().keys()
+ fields1 = fields or list(self.fields_get())
group_fields, other_fields = partition(is_reified_group, fields1)
# read regular fields (other_fields); add 'groups_id' if necessary
diff --git a/odoo/addons/base/tests/test_api.py b/odoo/addons/base/tests/test_api.py
index 8270d6086d5..55cf1ff26b5 100644
--- a/odoo/addons/base/tests/test_api.py
+++ b/odoo/addons/base/tests/test_api.py
@@ -79,11 +79,11 @@ class TestAPI(common.TransactionCase):
domain = [('name', 'ilike', 'j')]
partners = self.env['res.partner'].search(domain)
self.assertTrue(partners)
- ids = map(int, partners)
+ ids = partners.ids
# modify those partners, and check that partners has not changed
partners.write({'active': False})
- self.assertEqual(ids, map(int, partners))
+ self.assertEqual(ids, partners.ids)
# redo the search, and check that the result is now empty
partners2 = self.env['res.partner'].search(domain)
@@ -98,7 +98,7 @@ class TestAPI(common.TransactionCase):
self.assertIsRecordset(user.groups_id, 'res.groups')
partners = self.env['res.partner'].search([])
- for name, field in partners._fields.iteritems():
+ for name, field in pycompat.items(partners._fields):
if field.type == 'many2one':
for p in partners:
self.assertIsRecord(p[name], field.comodel_name)
@@ -296,7 +296,7 @@ class TestAPI(common.TransactionCase):
self.assertItemsEqual(partners.ids, country_id_cache)
# partners' countries are ready for prefetching
- country_ids = set(cid for cids in country_id_cache.itervalues() for cid in cids)
+ country_ids = set(cid for cids in pycompat.values(country_id_cache) for cid in cids)
self.assertTrue(len(country_ids) > 1)
self.assertItemsEqual(country_ids, partners._prefetch['res.country'])
diff --git a/odoo/addons/base/tests/test_expression.py b/odoo/addons/base/tests/test_expression.py
index 4dea4797b0c..87099e78754 100644
--- a/odoo/addons/base/tests/test_expression.py
+++ b/odoo/addons/base/tests/test_expression.py
@@ -5,7 +5,7 @@ import psycopg2
from odoo.models import BaseModel
from odoo.tests.common import TransactionCase
-from odoo.tools import mute_logger
+from odoo.tools import mute_logger, pycompat
import odoo.osv.expression as expression
@@ -85,10 +85,10 @@ class TestExpression(TransactionCase):
'b ab': [cids['B'], cids['AB']],
}
pids = {}
- for name, cat_ids in partners_config.iteritems():
+ for name, cat_ids in pycompat.items(partners_config):
pids[name] = partners.create({'name': name, 'category_id': [(6, 0, cat_ids)]}).id
- base_domain = [('id', 'in', pids.values())]
+ base_domain = [('id', 'in', list(pycompat.values(pids)))]
def test(op, value, expected):
found_ids = partners.search(base_domain + [('category_id', op, value)]).ids
diff --git a/odoo/addons/base/tests/test_float.py b/odoo/addons/base/tests/test_float.py
index 8c4ee380bd2..725ba48365b 100644
--- a/odoo/addons/base/tests/test_float.py
+++ b/odoo/addons/base/tests/test_float.py
@@ -98,10 +98,10 @@ 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 pycompat.range(7):
- for frac, exp, prec in zip(fractions, expecteds, precisions):
+ for magnitude in range(7):
+ for frac, exp, prec in pycompat.izip(fractions, expecteds, precisions):
for sign in [-1,1]:
- for x in pycompat.range(0, 10000, 97):
+ for x in range(0, 10000, 97):
n = x * 10 ** magnitude
f = sign * (n + frac)
f_exp = ('-' if f != 0 and sign == -1 else '') + str(n) + exp
diff --git a/odoo/addons/base/tests/test_ir_filters.py b/odoo/addons/base/tests/test_ir_filters.py
index d932f16be11..b8de7590ad2 100644
--- a/odoo/addons/base/tests/test_ir_filters.py
+++ b/odoo/addons/base/tests/test_ir_filters.py
@@ -4,11 +4,12 @@
from odoo import exceptions
from odoo.tests.common import TransactionCase, ADMIN_USER_ID
-def noid(d):
+def noid(seq):
""" Removes values that are not relevant for the test comparisons """
- d.pop('id', None)
- d.pop('action_id', None)
- return d
+ for d in seq:
+ d.pop('id', None)
+ d.pop('action_id', None)
+ return seq
class FiltersCase(TransactionCase):
@@ -34,7 +35,7 @@ class TestGetFilters(FiltersCase):
filters = self.env['ir.filters'].sudo(self.USER_ID).get_filters('ir.filters')
- self.assertItemsEqual(map(noid, filters), [
+ self.assertItemsEqual(noid(filters), [
dict(name='a', is_default=False, user_id=self.USER_NG, domain='[]', context='{}', sort='[]'),
dict(name='b', is_default=False, user_id=self.USER_NG, domain='[]', context='{}', sort='[]'),
dict(name='c', is_default=False, user_id=self.USER_NG, domain='[]', context='{}', sort='[]'),
@@ -52,7 +53,7 @@ class TestGetFilters(FiltersCase):
filters = self.env['ir.filters'].sudo(self.USER_ID).get_filters('ir.filters')
- self.assertItemsEqual(map(noid, filters), [
+ self.assertItemsEqual(noid(filters), [
dict(name='a', is_default=False, user_id=False, domain='[]', context='{}', sort='[]'),
dict(name='b', is_default=False, user_id=False, domain='[]', context='{}', sort='[]'),
dict(name='c', is_default=False, user_id=False, domain='[]', context='{}', sort='[]'),
@@ -69,7 +70,7 @@ class TestGetFilters(FiltersCase):
filters = self.env['ir.filters'].sudo(self.USER_ID).get_filters('ir.filters')
- self.assertItemsEqual(map(noid, filters), [
+ self.assertItemsEqual(noid(filters), [
dict(name='a', is_default=False, user_id=False, domain='[]', context='{}', sort='[]'),
dict(name='c', is_default=False, user_id=self.USER_NG, domain='[]', context='{}', sort='[]'),
])
@@ -95,7 +96,7 @@ class TestOwnDefaults(FiltersCase):
})
filters = Filters.get_filters('ir.filters')
- self.assertItemsEqual(map(noid, filters), [
+ self.assertItemsEqual(noid(filters), [
dict(name='a', user_id=self.USER_NG, is_default=True,
domain='[]', context='{}', sort='[]')
])
@@ -120,7 +121,7 @@ class TestOwnDefaults(FiltersCase):
})
filters = Filters.get_filters('ir.filters')
- self.assertItemsEqual(map(noid, filters), [
+ self.assertItemsEqual(noid(filters), [
dict(name='a', user_id=self.USER_NG, is_default=False, domain='[]', context='{}', sort='[]'),
dict(name='b', user_id=self.USER_NG, is_default=False, domain='[]', context='{}', sort='[]'),
dict(name='c', user_id=self.USER_NG, is_default=True, domain='[]', context='{}', sort='[]'),
@@ -146,7 +147,7 @@ class TestOwnDefaults(FiltersCase):
})
filters = Filters.get_filters('ir.filters')
- self.assertItemsEqual(map(noid, filters), [
+ self.assertItemsEqual(noid(filters), [
dict(name='a', user_id=self.USER_NG, is_default=False, domain='[]', context='{}', sort='[]'),
dict(name='b', user_id=self.USER_NG, is_default=False, domain='[]', context='{}', sort='[]'),
dict(name='c', user_id=self.USER_NG, is_default=True, domain='[]', context='{}', sort='[]'),
@@ -172,7 +173,7 @@ class TestOwnDefaults(FiltersCase):
})
filters = Filters.get_filters('ir.filters')
- self.assertItemsEqual(map(noid, filters), [
+ self.assertItemsEqual(noid(filters), [
dict(name='a', user_id=self.USER_NG, is_default=True, domain='[]', context='{}', sort='[]'),
dict(name='b', user_id=self.USER_NG, is_default=False, domain='[]', context='{}', sort='[]'),
])
@@ -204,7 +205,7 @@ class TestGlobalDefaults(FiltersCase):
})
filters = Filters.get_filters('ir.filters')
- self.assertItemsEqual(map(noid, filters), [
+ self.assertItemsEqual(noid(filters), [
dict(name='a', user_id=False, is_default=False, domain='[]', context='{}', sort='[]'),
dict(name='b', user_id=False, is_default=False, domain='[]', context='{}', sort='[]'),
dict(name='c', user_id=False, is_default=True, domain='[]', context='{}', sort='[]'),
@@ -271,7 +272,7 @@ class TestGlobalDefaults(FiltersCase):
})
filters = Filters.get_filters('ir.filters')
- self.assertItemsEqual(map(noid, filters), [
+ self.assertItemsEqual(noid(filters), [
dict(name='a', user_id=False, is_default=False, domain='[]', context='{}', sort='[]'),
dict(name='b', user_id=False, is_default=True, domain='[]', context=context_value, sort='[]'),
])
diff --git a/odoo/addons/base/tests/test_orm.py b/odoo/addons/base/tests/test_orm.py
index 0da71a84ad5..bf95bee08f7 100644
--- a/odoo/addons/base/tests/test_orm.py
+++ b/odoo/addons/base/tests/test_orm.py
@@ -141,7 +141,7 @@ class TestORM(TransactionCase):
partner_ids_by_year = defaultdict(list)
partners = self.env['res.partner']
- for name, date in partners_data.items():
+ for name, date in pycompat.items(partners_data):
p = partners.create(dict(name=name, date=date))
partner_ids.append(p.id)
partner_ids_by_day[date].append(p.id)
@@ -297,7 +297,7 @@ class TestO2MSerialization(TransactionCase):
def test_CREATE_commands(self):
" returns the VALUES dict as-is "
values = [{'foo': 'bar'}, {'foo': 'baz'}, {'foo': 'baq'}]
- results = self.env['res.partner'].resolve_2many_commands('child_ids', map(CREATE, values))
+ results = self.env['res.partner'].resolve_2many_commands('child_ids', [CREATE(v) for v in values])
self.assertEqual(results, values)
def test_LINK_TO_command(self):
@@ -307,7 +307,7 @@ class TestO2MSerialization(TransactionCase):
self.env['res.partner'].create({'name': 'bar'}).id,
self.env['res.partner'].create({'name': 'baz'}).id,
]
- commands = map(LINK_TO, ids)
+ commands = [LINK_TO(v) for v in ids]
results = self.env['res.partner'].resolve_2many_commands('child_ids', commands, ['name'])
self.assertItemsEqual(results, [
@@ -356,7 +356,7 @@ class TestO2MSerialization(TransactionCase):
self.env['res.partner'].create({'name': 'bar'}).id,
self.env['res.partner'].create({'name': 'baz'}).id,
]
- commands = map(DELETE, ids)
+ commands = [DELETE(v) for v in ids]
results = self.env['res.partner'].resolve_2many_commands('child_ids', commands, ['name'])
self.assertEqual(results, [])
diff --git a/odoo/addons/base/tests/test_qweb.py b/odoo/addons/base/tests/test_qweb.py
index dcf41b092d6..cd459fe7669 100644
--- a/odoo/addons/base/tests/test_qweb.py
+++ b/odoo/addons/base/tests/test_qweb.py
@@ -13,6 +13,7 @@ from itertools import chain
from odoo.modules import get_module_resource
from odoo.tests.common import TransactionCase
from odoo.addons.base.ir.ir_qweb import QWebException
+from odoo.tools import pycompat
def dedent_and_strip(string):
@@ -411,7 +412,7 @@ class TestQWebNS(TransactionCase):
'cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2',
'cbc': 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2'
}
- self.assertSetEqual(set(expected_ns.items()) - set(result_etree.nsmap.items()), set())
+ self.assertSetEqual(set(pycompat.items(expected_ns)) - set(pycompat.items(result_etree.nsmap)), set())
# check that the t-call did its work
cac_lines = result_etree.findall('.//cac:line', namespaces={'cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2'})
diff --git a/odoo/addons/base/tests/test_search.py b/odoo/addons/base/tests/test_search.py
index d52cd9db9c4..97670fdd805 100644
--- a/odoo/addons/base/tests/test_search.py
+++ b/odoo/addons/base/tests/test_search.py
@@ -2,6 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.tests.common import TransactionCase
+from odoo.tools import pycompat
class test_search(TransactionCase):
@@ -107,7 +108,7 @@ class test_search(TransactionCase):
user_ids[u] = Users.create({'name': u, 'login': u}).id
cron_ids[u] = Cron.create({'name': u, 'model_id': self.env.ref('base.model_res_partner').id, 'user_id': user_ids[u]}).id
- ids = Cron.search([('id', 'in', cron_ids.values())], order='user_id').ids
+ ids = Cron.search([('id', 'in', list(pycompat.values(cron_ids)))], order='user_id').ids
expected_ids = [cron_ids[l] for l in 'ABC']
self.assertEqual(ids, expected_ids)
@@ -127,7 +128,7 @@ class test_search(TransactionCase):
create('F', parent_id=cat_ids['D'])
expected_ids = [cat_ids[x] for x in 'ADEFBC']
- found_ids = Cats.search([('id', 'in', cat_ids.values())]).ids
+ found_ids = Cats.search([('id', 'in', list(pycompat.values(cat_ids)))]).ids
self.assertEqual(found_ids, expected_ids)
def test_13_m2o_order_loop_multi(self):
diff --git a/odoo/addons/base/tests/test_views.py b/odoo/addons/base/tests/test_views.py
index bd462932e5f..40cd922340c 100644
--- a/odoo/addons/base/tests/test_views.py
+++ b/odoo/addons/base/tests/test_views.py
@@ -638,7 +638,7 @@ class TestViews(ViewCase):
kw.setdefault('mode', 'extension' if kw.get('inherit_id') else 'primary')
kw.setdefault('active', True)
- keys = sorted(kw.keys())
+ keys = sorted(kw)
fields = ','.join('"%s"' % (k.replace('"', r'\"'),) for k in keys)
params = ','.join('%%(%s)s' % (k,) for k in keys)
diff --git a/odoo/addons/test_impex/tests/test_export.py b/odoo/addons/test_impex/tests/test_export.py
index 226ba9943f6..72a3b2a6f75 100644
--- a/odoo/addons/test_impex/tests/test_export.py
+++ b/odoo/addons/test_impex/tests/test_export.py
@@ -4,6 +4,7 @@
import itertools
from odoo.tests import common
+from odoo.tools import pycompat
class CreatorCase(common.TransactionCase):
@@ -494,9 +495,9 @@ class test_o2m_multiple(CreatorCase):
"""
fields = ['const', 'child1/value', 'child2/value']
child1 = [(0, False, {'value': v, 'str': 'record%.02d' % index})
- for index, v in zip(itertools.count(), [4, 42, 36, 4, 13])]
+ for index, v in pycompat.izip(itertools.count(), [4, 42, 36, 4, 13])]
child2 = [(0, False, {'value': v, 'str': 'record%.02d' % index})
- for index, v in zip(itertools.count(10), [8, 12, 8, 55, 33, 13])]
+ for index, v in pycompat.izip(itertools.count(10), [8, 12, 8, 55, 33, 13])]
self.assertEqual(
self.export(child1=child1, child2=False, fields=fields),
diff --git a/odoo/addons/test_limits/models.py b/odoo/addons/test_limits/models.py
index 506578a811b..957e3c3d6f9 100644
--- a/odoo/addons/test_limits/models.py
+++ b/odoo/addons/test_limits/models.py
@@ -5,7 +5,6 @@ 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
@@ -39,7 +38,7 @@ class m(models.Model):
t0 = time.clock()
t1 = time.clock()
while t1 - t0 < seconds:
- for i in pycompat.range(10000000):
+ for i in range(10000000):
x = i * i
t1 = time.clock()
return True
diff --git a/odoo/addons/test_new_api/models.py b/odoo/addons/test_new_api/models.py
index c84827d47ce..2f288e89f74 100644
--- a/odoo/addons/test_new_api/models.py
+++ b/odoo/addons/test_new_api/models.py
@@ -5,6 +5,7 @@ import datetime
from odoo import models, fields, api, _
from odoo.exceptions import AccessError, ValidationError
+from odoo.tools import pycompat
class Category(models.Model):
@@ -45,7 +46,7 @@ class Category(models.Model):
categories.append(category[0])
categories.append(self)
# assign parents following sequence
- for parent, child in zip(categories, categories[1:]):
+ for parent, child in pycompat.izip(categories, categories[1:]):
if parent and child:
child.parent = parent
# assign name of last category, and reassign display_name (to normalize it)
@@ -364,4 +365,4 @@ class ComputeRecursive(models.Model):
if rec.parent:
rec.display_name = rec.parent.display_name + " / " + rec.name
else:
- rec.display_name = rec.name \ No newline at end of file
+ rec.display_name = rec.name
diff --git a/odoo/addons/test_new_api/tests/test_one2many.py b/odoo/addons/test_new_api/tests/test_one2many.py
index 9ade2c0fe19..e1ad547e95e 100644
--- a/odoo/addons/test_new_api/tests/test_one2many.py
+++ b/odoo/addons/test_new_api/tests/test_one2many.py
@@ -45,7 +45,7 @@ class One2manyCase(TransactionCase):
# Check the lines first
self.assertItemsEqual(
self.multi.lines.mapped('name'),
- map(str, range(10)))
+ [str(i) for i in range(10)])
# Modify the first line and drop the last one
self.multi.lines[0].name = "hello"
self.multi.lines = self.multi.lines[:-1]
diff --git a/odoo/addons/test_pylint/tests/test_pylint.py b/odoo/addons/test_pylint/tests/test_pylint.py
index 1ae544e56a6..f98dcf88b3c 100644
--- a/odoo/addons/test_pylint/tests/test_pylint.py
+++ b/odoo/addons/test_pylint/tests/test_pylint.py
@@ -30,22 +30,33 @@ class TestPyLint(TransactionCase):
'relative-import',
'deprecated-module',
'import-star-module-level',
- # 'bad-python3-import', # TODO: more stuff used in report
+
+ 'bad-builtin',
+
+ 'dict-iter-method',
+ 'dict-view-method',
'long-suffix',
- 'apply-builtin',
- 'cmp-builtin',
- 'coerce-builtin',
- 'execfile-builtin',
- 'input-builtin',
- 'intern-builtin',
- 'long-builtin',
- 'raw_input-builtin',
- 'reload-builtin',
- 'xrange-builtin',
+ ]
+
+ BAD_FUNCTIONS = [
+ 'apply',
+ 'cmp',
+ 'coerce',
+ 'execfile',
+ 'input',
+ 'intern',
+ 'long',
+ 'raw_input',
+ 'reload',
+ 'xrange',
+ 'long',
+ 'map',
+ 'filter',
+ 'zip',
# TODO: enable once report has been removed
- # 'file-builtin',
- # 'reduce-builtin',
+ # 'file',
+ # 'reduce',
]
def _skip_test(self, reason):
@@ -69,6 +80,8 @@ class TestPyLint(TransactionCase):
'--enable=%s' % ','.join(self.ENABLED_CODES),
'--reports=n',
"--msg-template='{msg} ({msg_id}) at {path}:{line}'",
+ '--load-plugins=pylint.extensions.bad_builtin',
+ '--bad-functions=%s' % ','.join(self.BAD_FUNCTIONS),
]
try: