diff --git a/addons/account/models/account.py b/addons/account/models/account.py
index 29fcaa17c8e..daa407d636f 100644
--- a/addons/account/models/account.py
+++ b/addons/account/models/account.py
@@ -5,7 +5,7 @@ import math
from odoo.osv import expression
from odoo.tools.float_utils import float_round as round
-from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, pycompat
+from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
from odoo.exceptions import UserError, ValidationError
from odoo import api, fields, models, _
diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py
index 87480662784..ee0d1903fd0 100644
--- a/addons/account/models/account_invoice.py
+++ b/addons/account/models/account_invoice.py
@@ -395,7 +395,7 @@ class AccountInvoice(models.Model):
'_onchange_partner_id': ['account_id', 'payment_term_id', 'fiscal_position_id', 'partner_bank_id'],
'_onchange_journal_id': ['currency_id'],
}
- for onchange_method, changed_fields in pycompat.items(onchanges):
+ for onchange_method, changed_fields in onchanges.items():
if any(f not in vals for f in changed_fields):
invoice = self.new(vals)
getattr(invoice, onchange_method)()
@@ -516,7 +516,7 @@ class AccountInvoice(models.Model):
tax_grouped = invoice.get_taxes_values()
# Create new tax lines
- for tax in pycompat.values(tax_grouped):
+ for tax in tax_grouped.values():
account_invoice_tax.create(tax)
# dummy write on self to trigger recomputations
@@ -535,7 +535,7 @@ class AccountInvoice(models.Model):
def _onchange_invoice_line_ids(self):
taxes_grouped = self.get_taxes_values()
tax_lines = self.tax_line_ids.filtered('manual')
- for tax in pycompat.values(taxes_grouped):
+ for tax in taxes_grouped.values():
tax_lines += tax_lines.new(tax)
self.tax_line_ids = tax_lines
return
@@ -886,7 +886,7 @@ class AccountInvoice(models.Model):
else:
line2[tmp] = l
line = []
- for key, val in pycompat.items(line2):
+ for key, val in line2.items():
line.append((0, 0, val))
return line
@@ -1079,7 +1079,7 @@ class AccountInvoice(models.Model):
result = []
for line in lines:
values = {}
- for name, field in pycompat.items(line._fields):
+ for name, field in line._fields.items():
if name in MAGIC_COLUMNS:
continue
elif field.type == 'many2one':
@@ -1249,7 +1249,7 @@ class AccountInvoice(models.Model):
for line in self.tax_line_ids:
res.setdefault(line.tax_id.tax_group_id, 0.0)
res[line.tax_id.tax_group_id] += line.amount
- res = sorted(pycompat.items(res), key=lambda l: l[0].sequence)
+ res = sorted(res.items(), key=lambda l: l[0].sequence)
res = [(l[0].name, l[1]) for l in res]
return res
diff --git a/addons/account/models/chart_template.py b/addons/account/models/chart_template.py
index 2fe33e02e3a..d99b3fe99ce 100644
--- a/addons/account/models/chart_template.py
+++ b/addons/account/models/chart_template.py
@@ -7,8 +7,6 @@ from odoo.exceptions import UserError
import logging
-from odoo.tools import pycompat
-
_logger = logging.getLogger(__name__)
def migrate_set_tags_and_taxes_updatable(cr, registry, module):
@@ -327,7 +325,7 @@ class AccountChartTemplate(models.Model):
# writing account values after creation of accounts
company.transfer_account_id = account_template_ref[transfer_account_id.id]
- for key, value in pycompat.items(generated_tax_res['account_dict']):
+ for key, value in generated_tax_res['account_dict'].items():
if value['refund_account_id'] or value['account_id'] or value['cash_basis_account']:
AccountTaxObj.browse(key).write({
'refund_account_id': account_ref.get(value['refund_account_id'], False),
diff --git a/addons/account/models/partner.py b/addons/account/models/partner.py
index f2f0f85f7c0..de32aaa5f3d 100644
--- a/addons/account/models/partner.py
+++ b/addons/account/models/partner.py
@@ -5,7 +5,7 @@ from operator import itemgetter
import time
from odoo import api, fields, models, _
-from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, pycompat
+from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
from odoo.exceptions import ValidationError
from odoo.addons.base.res.res_partner import WARNING_MESSAGE, WARNING_HELP
@@ -73,7 +73,7 @@ class AccountFiscalPosition(models.Model):
ref_dict = {}
for line in self.account_ids:
ref_dict[line.account_src_id] = line.account_dest_id
- for key, acc in list(pycompat.items(accounts)):
+ for key, acc in accounts.items():
if acc in ref_dict:
accounts[key] = ref_dict[acc]
return accounts
@@ -293,7 +293,7 @@ class ResPartner(models.Model):
""" % where_clause
self.env.cr.execute(query, where_clause_params)
price_totals = self.env.cr.dictfetchall()
- for partner, child_ids in pycompat.items(all_partners_and_children):
+ for partner, child_ids in all_partners_and_children.items():
partner.total_invoiced = sum(price['total'] for price in price_totals if price['partner_id'] in child_ids)
@api.multi
diff --git a/addons/account/report/account_report_financial.py b/addons/account/report/account_report_financial.py
index 01e2080307f..65560736fff 100644
--- a/addons/account/report/account_report_financial.py
+++ b/addons/account/report/account_report_financial.py
@@ -3,7 +3,6 @@
import time
from odoo import api, models, _
from odoo.exceptions import UserError
-from odoo.tools import pycompat
class ReportFinancial(models.AbstractModel):
@@ -28,7 +27,7 @@ class ReportFinancial(models.AbstractModel):
if where_clause.strip():
wheres.append(where_clause.strip())
filters = " AND ".join(wheres)
- request = "SELECT account_id as id, " + ', '.join(pycompat.values(mapping)) + \
+ request = "SELECT account_id as id, " + ', '.join(mapping.values()) + \
" FROM " + tables + \
" WHERE account_id IN %s " \
+ filters + \
@@ -55,26 +54,26 @@ class ReportFinancial(models.AbstractModel):
if report.type == 'accounts':
# it's the sum of the linked accounts
res[report.id]['account'] = self._compute_account_balance(report.account_ids)
- for value in pycompat.values(res[report.id]['account']):
+ for value in res[report.id]['account'].values():
for field in fields:
res[report.id][field] += value.get(field)
elif report.type == 'account_type':
# it's the sum the leaf accounts with such an account type
accounts = self.env['account.account'].search([('user_type_id', 'in', report.account_type_ids.ids)])
res[report.id]['account'] = self._compute_account_balance(accounts)
- for value in pycompat.values(res[report.id]['account']):
+ for value in res[report.id]['account'].values():
for field in fields:
res[report.id][field] += value.get(field)
elif report.type == 'account_report' and report.account_report_id:
# it's the amount of the linked report
res2 = self._compute_report_balance(report.account_report_id)
- for key, value in pycompat.items(res2):
+ for key, value in res2.items():
for field in fields:
res[report.id][field] += value[field]
elif report.type == 'sum':
# it's the sum of the children of this account.report
res2 = self._compute_report_balance(report.children_ids)
- for key, value in pycompat.items(res2):
+ for key, value in res2.items():
for field in fields:
res[report.id][field] += value[field]
return res
@@ -86,11 +85,11 @@ class ReportFinancial(models.AbstractModel):
res = self.with_context(data.get('used_context'))._compute_report_balance(child_reports)
if data['enable_filter']:
comparison_res = self.with_context(data.get('comparison_context'))._compute_report_balance(child_reports)
- for report_id, value in pycompat.items(comparison_res):
+ for report_id, value in comparison_res.items():
res[report_id]['comp_bal'] = value['balance']
report_acc = res[report_id].get('account')
if report_acc:
- for account_id, val in pycompat.items(comparison_res[report_id].get('account')):
+ for account_id, val in comparison_res[report_id].get('account').items():
report_acc[account_id]['comp_bal'] = val['balance']
for report in child_reports:
@@ -115,7 +114,7 @@ class ReportFinancial(models.AbstractModel):
if res[report.id].get('account'):
sub_lines = []
- for account_id, value in pycompat.items(res[report.id]['account']):
+ for account_id, value in res[report.id]['account'].items():
#if there are accounts to display, we add them to the lines with a level equals to their level in
#the COA + 1 (to avoid having them with a too low level that would conflicts with the level of data
#financial reports for Assets, liabilities...)
diff --git a/addons/account/tests/test_reconciliation.py b/addons/account/tests/test_reconciliation.py
index 0093915eee5..ac2aca16951 100644
--- a/addons/account/tests/test_reconciliation.py
+++ b/addons/account/tests/test_reconciliation.py
@@ -2,8 +2,6 @@ from odoo.addons.account.tests.account_test_classes import AccountingTestCase
import time
import unittest
-from odoo.tools import pycompat
-
class TestReconciliation(AccountingTestCase):
@@ -339,8 +337,8 @@ class TestReconciliation(AccountingTestCase):
self.assertTrue(exchange_loss_line, 'There should be one move line of 0.01 EUR in credit')
# The journal items of the reconciliation should have their debit and credit total equal
# Besides, the total debit and total credit should be 60.61 EUR (2.00 USD)
- self.assertEquals(sum(res['debit'] for res in pycompat.values(result)), 60.61)
- self.assertEquals(sum(res['credit'] for res in pycompat.items(result)), 60.61)
+ self.assertEquals(sum(res['debit'] for res in result.values()), 60.61)
+ self.assertEquals(sum(res['credit'] for res in result.items()), 60.61)
counterpart_exchange_loss_line = None
for line in exchange_loss_line.move_id.line_id:
if line.account_id.id == self.account_fx_expense_id:
diff --git a/addons/account_asset/models/account_asset.py b/addons/account_asset/models/account_asset.py
index cc2a29a09a9..15d471301b6 100644
--- a/addons/account_asset/models/account_asset.py
+++ b/addons/account_asset/models/account_asset.py
@@ -7,7 +7,7 @@ from dateutil.relativedelta import relativedelta
from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError
-from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF, pycompat
+from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF
from odoo.tools import float_compare, float_is_zero
@@ -374,7 +374,7 @@ class AccountAssetAsset(models.Model):
vals = self.onchange_category_id_values(self.category_id.id)
# We cannot use 'write' on an object that doesn't exist yet
if vals:
- for k, v in pycompat.items(vals['value']):
+ for k, v in vals['value'].items():
setattr(self, k, v)
def onchange_category_id_values(self, category_id):
@@ -583,7 +583,7 @@ class AccountAssetDepreciationLine(models.Model):
message = ''
if message_description:
message = '%s' % message_description
- for name, values in pycompat.items(tracked_values):
+ for name, values in tracked_values.items():
message += '
• %s: ' % name
message += '%s
' % values
return message
diff --git a/addons/account_voucher/models/account_voucher.py b/addons/account_voucher/models/account_voucher.py
index e394af36296..40ae66c3395 100644
--- a/addons/account_voucher/models/account_voucher.py
+++ b/addons/account_voucher/models/account_voucher.py
@@ -5,7 +5,6 @@
from odoo import fields, models, api, _
from odoo.addons import decimal_precision as dp
from odoo.exceptions import UserError
-from odoo.tools import pycompat
class AccountVoucher(models.Model):
@@ -358,7 +357,7 @@ class AccountVoucherLine(models.Model):
self.company_id.id,
self.voucher_id.currency_id.id,
self.voucher_id.voucher_type)
- for fname, fvalue in pycompat.items(onchange_res['value']):
+ for fname, fvalue in onchange_res['value'].items():
setattr(self, fname, fvalue)
def _get_account(self, product, fpos, type):
diff --git a/addons/auth_signup/controllers/main.py b/addons/auth_signup/controllers/main.py
index 8f8db0fab0d..262dfdad86d 100644
--- a/addons/auth_signup/controllers/main.py
+++ b/addons/auth_signup/controllers/main.py
@@ -8,7 +8,6 @@ from odoo.addons.auth_signup.models.res_users import SignupError
from odoo.addons.web.controllers.main import ensure_db, Home
from odoo.exceptions import UserError
from odoo.http import request
-from odoo.tools import pycompat
_logger = logging.getLogger(__name__)
@@ -106,7 +105,7 @@ class AuthSignupHome(Home):
try:
# retrieve the user info (name, login or email) corresponding to a signup token
token_infos = request.env['res.partner'].sudo().signup_retrieve_info(qcontext.get('token'))
- for k, v in pycompat.items(token_infos):
+ for k, v in token_infos.items():
qcontext.setdefault(k, v)
except:
qcontext['error'] = _("Invalid signup token")
diff --git a/addons/auth_signup/models/res_partner.py b/addons/auth_signup/models/res_partner.py
index 0cf5c25b7ff..ecf63246580 100644
--- a/addons/auth_signup/models/res_partner.py
+++ b/addons/auth_signup/models/res_partner.py
@@ -8,8 +8,6 @@ from collections import defaultdict
from datetime import datetime, timedelta
from odoo import api, exceptions, fields, models, _
-from odoo.tools import pycompat
-
class SignupError(Exception):
pass
diff --git a/addons/base_address_extended/models/base_address_extended.py b/addons/base_address_extended/models/base_address_extended.py
index 1d49c1c94c4..9a210dde769 100644
--- a/addons/base_address_extended/models/base_address_extended.py
+++ b/addons/base_address_extended/models/base_address_extended.py
@@ -5,7 +5,6 @@ import re
from odoo import api, fields, models, _
from odoo.exceptions import UserError
-from odoo.tools import pycompat
STREET_FIELDS = ('street_name', 'street_number', 'street_number2')
@@ -135,7 +134,7 @@ class Partner(models.Model):
vals[field_name] = street_raw
# assign the values to the fields
# /!\ Note that a write(vals) would cause a recursion since it would bypass the cache
- for k, v in pycompat.items(vals):
+ for k, v in vals.items():
partner[k] = v
diff --git a/addons/base_automation/models/base_automation.py b/addons/base_automation/models/base_automation.py
index 061828c161e..9896a9706d8 100644
--- a/addons/base_automation/models/base_automation.py
+++ b/addons/base_automation/models/base_automation.py
@@ -12,7 +12,6 @@ from dateutil.relativedelta import relativedelta
from odoo import api, fields, models, SUPERUSER_ID
from odoo.modules.registry import Registry
-from odoo.tools import pycompat
from odoo.tools.safe_eval import safe_eval
_logger = logging.getLogger(__name__)
@@ -264,7 +263,7 @@ class BaseAutomation(models.Model):
if res:
if 'value' in res:
res['value'].pop('id', None)
- self.update({key: val for key, val in pycompat.items(res['value']) if key in self._fields})
+ self.update({key: val for key, val in res['value'].items() if key in self._fields})
if 'domain' in res:
result.setdefault('domain', {}).update(res['domain'])
if 'warning' in res:
diff --git a/addons/base_gengo/wizard/base_gengo_translations.py b/addons/base_gengo/wizard/base_gengo_translations.py
index 98df9356576..d6e5ce9176a 100644
--- a/addons/base_gengo/wizard/base_gengo_translations.py
+++ b/addons/base_gengo/wizard/base_gengo_translations.py
@@ -8,7 +8,6 @@ import uuid
from odoo import api, fields, models, tools, _
from odoo.exceptions import UserError, ValidationError
-from odoo.tools import pycompat
_logger = logging.getLogger(__name__)
@@ -194,7 +193,7 @@ class BaseGengoTranslations(models.TransientModel):
term_ids.write(vals)
jobs = response.get('jobs', [])
if jobs:
- for t_id, job in pycompat.items(jobs):
+ for t_id, job in jobs.items():
self._update_terms_job(job)
return
diff --git a/addons/base_import/models/base_import.py b/addons/base_import/models/base_import.py
index 09d2dcb2852..19941858dfa 100644
--- a/addons/base_import/models/base_import.py
+++ b/addons/base_import/models/base_import.py
@@ -42,7 +42,7 @@ FILE_TYPE_DICT = {
}
EXTENSIONS = {
'.' + ext: handler
- for mime, (ext, handler, req) in pycompat.items(FILE_TYPE_DICT)
+ for mime, (ext, handler, req) in FILE_TYPE_DICT.items()
}
@@ -114,7 +114,7 @@ class Import(models.TransientModel):
}]
model_fields = Model.fields_get()
blacklist = models.MAGIC_COLUMNS + [Model.CONCURRENCY_CHECK_FIELD]
- for name, field in pycompat.items(model_fields):
+ for name, field in model_fields.items():
if name in blacklist:
continue
# an empty string means the field is deprecated, @deprecated must
@@ -127,7 +127,7 @@ class Import(models.TransientModel):
continue
# states = {state: [(attr, value), (attr2, value2)], state2:...}
if not any(attr == 'readonly' and value is False
- for attr, value in itertools.chain.from_iterable(pycompat.values(states))):
+ for attr, value in itertools.chain.from_iterable(states.values())):
continue
field_value = {
'id': name,
@@ -595,7 +595,7 @@ class Import(models.TransientModel):
def _parse_import_data(self, data, import_fields, options):
# Get fields of type date/datetime
all_fields = self.env[self.res_model].fields_get()
- for name, field in pycompat.items(all_fields):
+ for name, field in all_fields.items():
if field['type'] in ('date', 'datetime') and name in import_fields:
# Parse date
index = import_fields.index(name)
diff --git a/addons/base_import/models/odf_ods_reader.py b/addons/base_import/models/odf_ods_reader.py
index c2613c6baa5..daa7d2b16e2 100644
--- a/addons/base_import/models/odf_ods_reader.py
+++ b/addons/base_import/models/odf_ods_reader.py
@@ -19,8 +19,6 @@ from odf import opendocument
from odf.table import Table, TableRow, TableCell
from odf.text import P
-from odoo.tools import pycompat
-
class ODSReader(object):
@@ -97,4 +95,4 @@ class ODSReader(object):
return self.SHEETS[name]
def getFirstSheet(self):
- return next(iter(pycompat.values(self.SHEETS)))
+ return next(iter(self.SHEETS.values()))
diff --git a/addons/base_import_module/models/ir_module.py b/addons/base_import_module/models/ir_module.py
index d6bb62a4d46..5bad5ea53eb 100644
--- a/addons/base_import_module/models/ir_module.py
+++ b/addons/base_import_module/models/ir_module.py
@@ -9,7 +9,7 @@ from os.path import join as opj
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.modules import load_information_from_description_file
-from odoo.tools import convert_file, exception_to_unicode, pycompat
+from odoo.tools import convert_file, exception_to_unicode
from odoo.tools.osutil import tempdir
_logger = logging.getLogger(__name__)
@@ -119,6 +119,6 @@ class IrModule(models.Model):
finally:
addons.module.ad_paths.remove(module_dir)
r = ["Successfully imported module '%s'" % mod for mod in success]
- for mod, error in pycompat.items(errors):
+ for mod, error in errors.items():
r.append("Error while importing module '%s': %r" % (mod, error))
return '\n'.join(r), module_names
diff --git a/addons/calendar/models/calendar.py b/addons/calendar/models/calendar.py
index 49c87a8e9b9..e80a2727282 100644
--- a/addons/calendar/models/calendar.py
+++ b/addons/calendar/models/calendar.py
@@ -470,7 +470,7 @@ class Alarm(models.Model):
name = fields.Char('Name', required=True)
type = fields.Selection([('notification', 'Notification'), ('email', 'Email')], 'Type', required=True, default='email')
duration = fields.Integer('Remind Before', required=True, default=1)
- interval = fields.Selection(list(pycompat.items(_interval_selection)), 'Unit', required=True, default='hours')
+ interval = fields.Selection(list(_interval_selection.items()), 'Unit', required=True, default='hours')
duration_minutes = fields.Integer('Duration in minutes', compute='_compute_duration_minutes', store=True, help="Duration in minutes")
@api.onchange('duration', 'interval')
@@ -1292,7 +1292,7 @@ class Meeting(models.Model):
@api.multi
def _get_message_unread(self):
id_map = {x: calendar_id2real_id(x) for x in self.ids}
- real = self.browse(set(pycompat.values(id_map)))
+ real = self.browse(set(id_map.values()))
super(Meeting, real)._get_message_unread()
for event in self:
if event.id == id_map[event.id]:
@@ -1304,7 +1304,7 @@ class Meeting(models.Model):
@api.multi
def _get_message_needaction(self):
id_map = {x: calendar_id2real_id(x) for x in self.ids}
- real = self.browse(set(pycompat.values(id_map)))
+ real = self.browse(set(id_map.values()))
super(Meeting, real)._get_message_needaction()
for event in self:
if event.id == id_map[event.id]:
diff --git a/addons/event/models/event.py b/addons/event/models/event.py
index 95310a67122..c5f7f43915a 100644
--- a/addons/event/models/event.py
+++ b/addons/event/models/event.py
@@ -5,7 +5,6 @@ import pytz
from odoo import _, api, fields, models
from odoo.addons.mail.models.mail_template import format_tz
from odoo.exceptions import AccessError, UserError, ValidationError
-from odoo.tools import pycompat
from odoo.tools.translate import html_translate
from dateutil.relativedelta import relativedelta
@@ -389,7 +388,7 @@ class EventRegistration(models.Model):
'partner_id': partner_id.id,
'event_id': event_id and event_id.id or False,
}
- data.update({key: value for key, value in pycompat.items(registration) if key in self._fields})
+ data.update({key: value for key, value in registration.items() if key in self._fields})
return data
@api.one
diff --git a/addons/fleet/models/fleet_vehicle_cost.py b/addons/fleet/models/fleet_vehicle_cost.py
index 12c6a7d7f2e..827863e3adc 100644
--- a/addons/fleet/models/fleet_vehicle_cost.py
+++ b/addons/fleet/models/fleet_vehicle_cost.py
@@ -6,8 +6,6 @@ from odoo.exceptions import UserError
from dateutil.relativedelta import relativedelta
-from odoo.tools import pycompat
-
class FleetVehicleCost(models.Model):
_name = 'fleet.vehicle.cost'
@@ -264,7 +262,7 @@ class FleetVehicleLogContract(models.Model):
res[contract.vehicle_id.id] = 1
Vehicle = self.env['fleet.vehicle']
- for vehicle, value in pycompat.items(res):
+ for vehicle, value in res.items():
Vehicle.browse(vehicle).message_post(body=_('%s contract(s) need(s) to be renewed and/or closed!') % value)
return contracts.write({'state': 'toclose'})
diff --git a/addons/gamification/models/goal.py b/addons/gamification/models/goal.py
index 56c447dd9d4..3c062401662 100644
--- a/addons/gamification/models/goal.py
+++ b/addons/gamification/models/goal.py
@@ -262,7 +262,7 @@ class Goal(models.Model):
for goal in self:
goals_by_definition.setdefault(goal.definition_id, []).append(goal)
- for definition, goals in pycompat.items(goals_by_definition):
+ for definition, goals in goals_by_definition.items():
goals_to_write = {}
if definition.computation_mode == 'manually':
for goal in goals:
@@ -307,9 +307,9 @@ class Goal(models.Model):
subqueries.setdefault((start_date, end_date), {}).update({goal.id:safe_eval(definition.batch_user_expression, {'user': goal.user_id})})
# the global query should be split by time periods (especially for recurrent goals)
- for (start_date, end_date), query_goals in pycompat.items(subqueries):
+ for (start_date, end_date), query_goals in subqueries.items():
subquery_domain = list(general_domain)
- subquery_domain.append((field_name, 'in', list(set(pycompat.values(query_goals)))))
+ subquery_domain.append((field_name, 'in', list(set(query_goals.values()))))
if start_date:
subquery_domain.append((field_date_name, '>=', start_date))
if end_date:
@@ -353,7 +353,7 @@ class Goal(models.Model):
goals_to_write.update(goal._get_write_values(new_value))
- for goal, values in pycompat.items(goals_to_write):
+ for goal, values in goals_to_write.items():
if not values:
continue
goal.write(values)
diff --git a/addons/google_calendar/models/google_calendar.py b/addons/google_calendar/models/google_calendar.py
index 0303dbe5154..ac91835f530 100644
--- a/addons/google_calendar/models/google_calendar.py
+++ b/addons/google_calendar/models/google_calendar.py
@@ -12,7 +12,7 @@ import pytz
from werkzeug import urls
from odoo import api, fields, models, tools, _
-from odoo.tools import exception_to_unicode, pycompat
+from odoo.tools import exception_to_unicode
_logger = logging.getLogger(__name__)
@@ -25,15 +25,13 @@ class Meta(type):
""" This Meta class allow to define class as a structure, and so instancied variable
in __init__ to avoid to have side effect alike 'static' variable """
def __new__(typ, name, parents, attrs):
- methods = {k: v for k, v in pycompat.items(attrs)
- if callable(v)}
- attrs = {k: v for k, v in pycompat.items(attrs)
- if not callable(v)}
+ methods = {k: v for k, v in attrs.items() if callable(v)}
+ attrs = {k: v for k, v in attrs.items() if not callable(v)}
def init(self, **kw):
- for key, val in pycompat.items(attrs):
+ for key, val in attrs.items():
setattr(self, key, val)
- for key, val in pycompat.items(kw):
+ for key, val in kw.items():
assert key in attrs
setattr(self, key, val)
@@ -161,7 +159,7 @@ class SyncOperation(object):
def __init__(self, src, info, **kw):
self.src = src
self.info = info
- for key, val in pycompat.items(kw):
+ for key, val in kw.items():
setattr(self, key, val)
def __str__(self):
@@ -689,7 +687,7 @@ class GoogleCalendar(models.AbstractModel):
my_google_attendees = CalendarAttendee.with_context(context_novirtual).search([
('partner_id', '=', my_partner_id),
- ('google_internal_event_id', 'in', pycompat.keys(all_event_from_google))
+ ('google_internal_event_id', 'in', all_event_from_google.keys())
])
my_google_att_ids = my_google_attendees.ids
@@ -753,7 +751,7 @@ class GoogleCalendar(models.AbstractModel):
ev_to_sync.OE.status = event.active
ev_to_sync.OE.synchro = att.oe_synchro_date
- for event in pycompat.values(all_event_from_google):
+ for event in all_event_from_google.values():
event_id = event.get('id')
base_event_id = event_id.rsplit('_', 1)[0]
@@ -788,7 +786,7 @@ class GoogleCalendar(models.AbstractModel):
# DO ACTION #
######################
for base_event in event_to_synchronize:
- event_to_synchronize[base_event] = sorted(pycompat.items(event_to_synchronize[base_event]), key=operator.itemgetter(0))
+ event_to_synchronize[base_event] = sorted(event_to_synchronize[base_event].items(), key=operator.itemgetter(0))
for current_event in event_to_synchronize[base_event]:
self.env.cr.commit()
event = current_event[1] # event is an Sync Event !
diff --git a/addons/hr/models/hr.py b/addons/hr/models/hr.py
index 3e513bb9e5d..d3bb213cb6a 100644
--- a/addons/hr/models/hr.py
+++ b/addons/hr/models/hr.py
@@ -7,7 +7,6 @@ from odoo import api, fields, models
from odoo import tools, _
from odoo.exceptions import ValidationError
from odoo.modules.module import get_module_resource
-from odoo.tools import pycompat
_logger = logging.getLogger(__name__)
@@ -250,7 +249,7 @@ class Employee(models.Model):
if auto_follow_fields is None:
auto_follow_fields = ['user_id']
user_field_lst = []
- for name, field in pycompat.items(self._fields):
+ for name, field in self._fields.items():
if name in auto_follow_fields and name in updated_fields and field.comodel_name == 'res.users':
user_field_lst.append(name)
return user_field_lst
diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py
index ce0054a5636..6699dddeb2a 100644
--- a/addons/hr_expense/models/hr_expense.py
+++ b/addons/hr_expense/models/hr_expense.py
@@ -5,7 +5,7 @@ import re
from odoo import api, fields, models, _
from odoo.exceptions import UserError
-from odoo.tools import email_split, float_is_zero, pycompat
+from odoo.tools import email_split, float_is_zero
from odoo.addons import decimal_precision as dp
@@ -243,7 +243,7 @@ class HrExpense(models.Model):
expense.sheet_id.write({'account_move_id': move.id})
if expense.payment_mode == 'company_account':
expense.sheet_id.paid_expense_sheets()
- for move in pycompat.values(move_group_by_sheet):
+ for move in move_group_by_sheet.values():
move.post()
return True
diff --git a/addons/hr_payroll/models/hr_payslip.py b/addons/hr_payroll/models/hr_payslip.py
index fd30b7a1b23..2f310c3456e 100644
--- a/addons/hr_payroll/models/hr_payslip.py
+++ b/addons/hr_payroll/models/hr_payslip.py
@@ -11,8 +11,6 @@ import babel
from odoo import api, fields, models, tools, _
from odoo.addons import decimal_precision as dp
from odoo.exceptions import UserError, ValidationError
-from odoo.tools import pycompat
-
class HrPayslip(models.Model):
_name = 'hr.payslip'
@@ -205,7 +203,7 @@ class HrPayslip(models.Model):
}
res.append(attendances)
- res.extend(pycompat.values(leaves))
+ res.extend(leaves.values())
return res
@api.model
@@ -369,7 +367,7 @@ class HrPayslip(models.Model):
#blacklist this rule and its children
blacklist += [id for id, seq in rule._recursive_search_of_rules()]
- return [value for code, value in pycompat.items(result_dict)]
+ return list(result_dict.values())
# YTI TODO To rename. This method is not really an onchange, as it is not in any view
# employee_id and contract_id could be browse records
diff --git a/addons/hr_payroll/report/report_payslip_details.py b/addons/hr_payroll/report/report_payslip_details.py
index 23043d2edb9..ffd5b9d913d 100644
--- a/addons/hr_payroll/report/report_payslip_details.py
+++ b/addons/hr_payroll/report/report_payslip_details.py
@@ -2,8 +2,6 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, models
-from odoo.tools import pycompat
-
class PayslipDetailsReport(models.AbstractModel):
_name = 'report.hr_payroll.report_payslipdetails'
@@ -38,9 +36,9 @@ class PayslipDetailsReport(models.AbstractModel):
result.setdefault(x[2], {})
result[x[2]].setdefault(x[1], [])
result[x[2]][x[1]].append(x[0])
- for payslip_id, lines_dict in pycompat.items(result):
+ for payslip_id, lines_dict in result.items():
res.setdefault(payslip_id, [])
- for rule_categ_id, line_ids in pycompat.items(lines_dict):
+ for rule_categ_id, line_ids in lines_dict.items():
rule_categories = RuleCateg.browse(rule_categ_id)
lines = PayslipLine.browse(line_ids)
level = 0
@@ -70,9 +68,9 @@ class PayslipDetailsReport(models.AbstractModel):
result.setdefault(line.slip_id.id, {})
result[line.slip_id.id].setdefault(line.register_id, line)
result[line.slip_id.id][line.register_id] |= line
- for payslip_id, lines_dict in pycompat.items(result):
+ for payslip_id, lines_dict in result.items():
res.setdefault(payslip_id, [])
- for register, lines in pycompat.items(lines_dict):
+ for register, lines in lines_dict.items():
res[payslip_id].append({
'register_name': register.name,
'total': sum(lines.mapped('total')),
diff --git a/addons/hr_recruitment/models/hr_recruitment.py b/addons/hr_recruitment/models/hr_recruitment.py
index adec7b15f57..4e4a694e9eb 100644
--- a/addons/hr_recruitment/models/hr_recruitment.py
+++ b/addons/hr_recruitment/models/hr_recruitment.py
@@ -4,7 +4,6 @@
from datetime import datetime
from odoo import api, fields, models, tools, SUPERUSER_ID
-from odoo.tools import pycompat
from odoo.tools.translate import _
from odoo.exceptions import UserError
@@ -251,7 +250,7 @@ class Applicant(models.Model):
self = self.with_context(default_department_id=vals.get('department_id'))
if vals.get('job_id') or self._context.get('default_job_id'):
job_id = vals.get('job_id') or self._context.get('default_job_id')
- for key, value in pycompat.items(self._onchange_job_id_internal(job_id)['value']):
+ for key, value in self._onchange_job_id_internal(job_id)['value'].items():
if key not in vals:
vals[key] = value
if vals.get('user_id'):
diff --git a/addons/im_livechat/models/im_livechat_channel.py b/addons/im_livechat/models/im_livechat_channel.py
index a878389913c..c2741fcef92 100644
--- a/addons/im_livechat/models/im_livechat_channel.py
+++ b/addons/im_livechat/models/im_livechat_channel.py
@@ -6,8 +6,6 @@ import re
from datetime import datetime, timedelta
from odoo import api, fields, models, modules, tools
-from odoo.tools import pycompat
-
class ImLivechatChannel(models.Model):
""" Livechat Channel
@@ -96,7 +94,7 @@ class ImLivechatChannel(models.Model):
for record in self:
dt = fields.Datetime.to_string(datetime.utcnow() - timedelta(days=7))
repartition = record.channel_ids.rating_get_grades([('create_date', '>=', dt)])
- total = sum(pycompat.values(repartition))
+ total = sum(repartition.values())
if total > 0:
happy = repartition['great']
record.rating_percentage_satisfaction = ((happy*100) / total) if happy > 0 else 0
diff --git a/addons/im_livechat/models/mail_channel.py b/addons/im_livechat/models/mail_channel.py
index 32d66a0154c..c64bcd7108c 100644
--- a/addons/im_livechat/models/mail_channel.py
+++ b/addons/im_livechat/models/mail_channel.py
@@ -2,8 +2,6 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
-from odoo.tools import pycompat
-
class ChannelPartner(models.Model):
_inherit = 'mail.channel.partner'
@@ -78,7 +76,7 @@ class MailChannel(models.Model):
last_msg = self.env['mail.message'].search([("channel_ids", "in", [channel.id])], limit=1)
if last_msg:
channel_infos_dict[channel.id]['last_message_date'] = last_msg.date
- return list(pycompat.values(channel_infos_dict))
+ return list(channel_infos_dict.values())
@api.model
def channel_fetch_slot(self):
diff --git a/addons/l10n_in_hr_payroll/report/report_hr_yearly_salary_detail.py b/addons/l10n_in_hr_payroll/report/report_hr_yearly_salary_detail.py
index 001a5a782f8..0d26efe9bf5 100644
--- a/addons/l10n_in_hr_payroll/report/report_hr_yearly_salary_detail.py
+++ b/addons/l10n_in_hr_payroll/report/report_hr_yearly_salary_detail.py
@@ -5,8 +5,6 @@ from datetime import date
from odoo import api, models, _
from odoo.exceptions import UserError
-from odoo.tools import pycompat
-
class EmployeesYearlySalaryReport(models.AbstractModel):
_name = 'report.l10n_in_hr_payroll.report_hryearlysalary'
@@ -99,7 +97,7 @@ class EmployeesYearlySalaryReport(models.AbstractModel):
def salary_list(self, salaries):
cat_salary_all = []
- for category_name, amount in pycompat.items(salaries):
+ for category_name, amount in salaries.items():
cat_salary = []
total = 0.0
cat_salary.append(category_name)
diff --git a/addons/l10n_lu/scripts/tax2csv.py b/addons/l10n_lu/scripts/tax2csv.py
index f4080284064..23fec3c734c 100644
--- a/addons/l10n_lu/scripts/tax2csv.py
+++ b/addons/l10n_lu/scripts/tax2csv.py
@@ -59,7 +59,7 @@ class LuxTaxGenerator:
if tax_code in tax_codes:
raise RuntimeError('duplicate tax code %s' % tax_code)
tax_codes[tax_code] = row['id']
- writer.writerow([pycompat.to_text(v) for v in pycompat.values(row)])
+ writer.writerow([pycompat.to_text(v) for v in row.values()])
# read taxes and add leaf tax codes
new_tax_codes = {} # id: parent_code
@@ -162,7 +162,7 @@ class LuxTaxGenerator:
cur_seq = seq
writer.writerow([
pycompat.to_text(v)
- for v in list(pycompat.values(row))[3:]
+ for v in list(row.values())[3:]
] + [cur_seq])
def fiscal_pos_map_to_csv(self):
@@ -173,7 +173,7 @@ class LuxTaxGenerator:
keys = next(fiscal_pos_map_iterator)
writer.writerow(keys)
for row in fiscal_pos_map_iterator:
- writer.writerow([pycompat.to_text(s) for s in pycompat.values(row)])
+ writer.writerow([pycompat.to_text(s) for s in row.values()])
if __name__ == '__main__':
diff --git a/addons/link_tracker/models/link_tracker.py b/addons/link_tracker/models/link_tracker.py
index da24f66e905..509fc21e153 100644
--- a/addons/link_tracker/models/link_tracker.py
+++ b/addons/link_tracker/models/link_tracker.py
@@ -12,7 +12,7 @@ from werkzeug import urls, utils
from odoo import models, fields, api, _
-from odoo.tools import ustr, pycompat
+from odoo.tools import ustr
URL_REGEX = r'(\bhref=[\'"](?!mailto:)([^\'"]+)[\'"])'
@@ -165,7 +165,7 @@ class link_tracker(models.Model):
create_vals['url'] = VALIDATE_URL(vals['url'])
search_domain = []
- for fname, value in pycompat.items(create_vals):
+ for fname, value in create_vals.items():
search_domain.append((fname, '=', value))
result = self.search(search_domain, limit=1)
diff --git a/addons/lunch/models/lunch.py b/addons/lunch/models/lunch.py
index ee8bba3492e..e9c13060fc3 100644
--- a/addons/lunch/models/lunch.py
+++ b/addons/lunch/models/lunch.py
@@ -10,8 +10,6 @@ from odoo import api, fields, models, _
from odoo.exceptions import AccessError, ValidationError
from odoo.addons import decimal_precision as dp
-from odoo.tools import pycompat
-
class LunchOrder(models.Model):
"""
@@ -26,10 +24,10 @@ class LunchOrder(models.Model):
prev_order = self.env['lunch.order.line'].search([('user_id', '=', self.env.uid), ('product_id.active', '!=', False)], limit=20, order='id desc')
# If we return return prev_order.ids, we will have duplicates (identical orders).
# Therefore, this following part removes duplicates based on product_id and note.
- return list(pycompat.values({
+ return list({
(order.product_id, order.note): order.id
for order in prev_order
- }))
+ }.values())
user_id = fields.Many2one('res.users', 'User', readonly=True,
states={'new': [('readonly', False)]},
@@ -88,10 +86,10 @@ class LunchOrder(models.Model):
prev_order = self.env['lunch.order.line'].search([('user_id', '=', self.env.uid), ('product_id.active', '!=', False)], limit=20, order='date desc, id desc')
# If we use prev_order.ids, we will have duplicates (identical orders).
# Therefore, this following part removes duplicates based on product_id and note.
- self.previous_order_ids = list(pycompat.values({
+ self.previous_order_ids = list({
(order.product_id, order.note): order.id
for order in prev_order
- }))
+ }.values())
if self.previous_order_ids:
lunch_data = {}
diff --git a/addons/mail/models/mail_channel.py b/addons/mail/models/mail_channel.py
index a2ac768b772..31e03b99081 100644
--- a/addons/mail/models/mail_channel.py
+++ b/addons/mail/models/mail_channel.py
@@ -9,7 +9,7 @@ import uuid
from odoo import _, api, fields, models, modules, tools
from odoo.exceptions import UserError
from odoo.osv import expression
-from odoo.tools import ormcache, pycompat
+from odoo.tools import ormcache
from odoo.tools.safe_eval import safe_eval
@@ -619,7 +619,7 @@ class Channel(models.Model):
channel = channels_preview[message['id']]
del(channel['message_id'])
channel['last_message'] = message
- return list(pycompat.values(channels_preview))
+ return list(channels_preview.values())
#------------------------------------------------------
# Commands
diff --git a/addons/mail/models/mail_followers.py b/addons/mail/models/mail_followers.py
index a6bd60f82c9..3edcfa748c3 100644
--- a/addons/mail/models/mail_followers.py
+++ b/addons/mail/models/mail_followers.py
@@ -2,7 +2,6 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
-from odoo.tools import pycompat
class Followers(models.Model):
@@ -42,7 +41,7 @@ class Followers(models.Model):
using the subtypes given in the parameters
"""
res_model_id = self.env['ir.model']._get(res_model).id
- force_mode = force or (all(data for data in pycompat.values(partner_data)) and all(data for data in pycompat.values(channel_data)))
+ force_mode = force or (all(partner_data.values()) and all(channel_data.values()))
generic = []
specific = {}
existing = {} # {res_id: follower_ids}
@@ -71,13 +70,13 @@ class Followers(models.Model):
if force_mode:
employee_pids = self.env['res.users'].sudo().search([('partner_id', 'in', list(partner_data)), ('share', '=', False)]).mapped('partner_id').ids
- for pid, data in pycompat.items(partner_data):
+ for pid, data in partner_data.items():
if not data:
if pid not in employee_pids:
partner_data[pid] = external_default_subtypes.ids
else:
partner_data[pid] = default_subtypes.ids
- for cid, data in pycompat.items(channel_data):
+ for cid, data in channel_data.items():
if not data:
channel_data[cid] = default_subtypes.ids
diff --git a/addons/mail/models/mail_mail.py b/addons/mail/models/mail_mail.py
index e53c24fb176..e723f71bdc6 100644
--- a/addons/mail/models/mail_mail.py
+++ b/addons/mail/models/mail_mail.py
@@ -13,7 +13,6 @@ from email.utils import formataddr
from odoo import _, api, fields, models
from odoo import tools
from odoo.addons.base.ir.ir_mail_server import MailDeliveryException
-from odoo.tools import pycompat
from odoo.tools.safe_eval import safe_eval
_logger = logging.getLogger(__name__)
@@ -205,7 +204,7 @@ class MailMail(models.Model):
groups[mail.mail_server_id.id].append(mail.id)
sys_params = self.env['ir.config_parameter'].sudo()
batch_size = int(sys_params.get_param('mail.session.batch.size', 1000))
- for server_id, record_ids in pycompat.items(groups):
+ for server_id, record_ids in groups.items():
for mail_batch in tools.split_every(batch_size, record_ids):
yield server_id, mail_batch
diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py
index 2970933e704..3675ca26332 100644
--- a/addons/mail/models/mail_message.py
+++ b/addons/mail/models/mail_message.py
@@ -9,7 +9,6 @@ from email.utils import formataddr
from odoo import _, api, fields, models, modules, SUPERUSER_ID, tools
from odoo.exceptions import UserError, AccessError
from odoo.osv import expression
-from odoo.tools import pycompat
_logger = logging.getLogger(__name__)
_image_dataurl = re.compile(r'(data:image/[a-z]+?);base64,([a-z0-9+/]{3,}=*)([\'"])', re.I)
@@ -282,7 +281,7 @@ class Message(models.Model):
partners = self.env['res.partner'].sudo()
attachments = self.env['ir.attachment']
trackings = self.env['mail.tracking.value']
- for key, message in pycompat.items(message_tree):
+ for key, message in message_tree.items():
if message.author_id:
partners |= message.author_id
if message.subtype_id and message.partner_ids: # take notified people of message with a subtype
@@ -446,7 +445,7 @@ class Message(models.Model):
def _find_allowed_doc_ids(self, model_ids):
IrModelAccess = self.env['ir.model.access']
allowed_ids = set()
- for doc_model, doc_dict in pycompat.items(model_ids):
+ for doc_model, doc_dict in model_ids.items():
if not IrModelAccess.check(doc_model, 'read', False):
continue
allowed_ids |= self._find_allowed_model_wise(doc_model, doc_dict)
@@ -607,17 +606,17 @@ class Message(models.Model):
# Author condition (READ, WRITE, CREATE (private))
author_ids = []
if operation == 'read' or operation == 'write':
- author_ids = [mid for mid, message in pycompat.items(message_values)
+ author_ids = [mid for mid, message in message_values.items()
if message.get('author_id') and message.get('author_id') == self.env.user.partner_id.id]
elif operation == 'create':
- author_ids = [mid for mid, message in pycompat.items(message_values)
+ author_ids = [mid for mid, message in message_values.items()
if not message.get('model') and not message.get('res_id')]
# Parent condition, for create (check for received notifications for the created message parent)
notified_ids = []
if operation == 'create':
# TDE: probably clean me
- parent_ids = [message.get('parent_id') for mid, message in pycompat.items(message_values)
+ parent_ids = [message.get('parent_id') for message in message_values.values()
if message.get('parent_id')]
self._cr.execute("""SELECT DISTINCT m.id, partner_rel.res_partner_id, channel_partner.partner_id FROM "%s" m
LEFT JOIN "mail_message_res_partner_rel" partner_rel
@@ -630,37 +629,37 @@ class Message(models.Model):
ON channel_partner.channel_id = channel.id AND channel_partner.partner_id = (%%s)
WHERE m.id = ANY (%%s)""" % self._table, (self.env.user.partner_id.id, self.env.user.partner_id.id, parent_ids,))
not_parent_ids = [mid[0] for mid in self._cr.fetchall() if any([mid[1], mid[2]])]
- notified_ids += [mid for mid, message in pycompat.items(message_values)
+ notified_ids += [mid for mid, message in message_values.items()
if message.get('parent_id') in not_parent_ids]
# Recipients condition, for read and write (partner_ids) and create (message_follower_ids)
other_ids = set(self.ids).difference(set(author_ids), set(notified_ids))
model_record_ids = _generate_model_record_ids(message_values, other_ids)
if operation in ['read', 'write']:
- notified_ids = [mid for mid, message in pycompat.items(message_values) if message.get('notified')]
+ notified_ids = [mid for mid, message in message_values.items() if message.get('notified')]
elif operation == 'create':
- for doc_model, doc_ids in pycompat.items(model_record_ids):
+ for doc_model, doc_ids in model_record_ids.items():
followers = self.env['mail.followers'].sudo().search([
('res_model', '=', doc_model),
('res_id', 'in', list(doc_ids)),
('partner_id', '=', self.env.user.partner_id.id),
])
fol_mids = [follower.res_id for follower in followers]
- notified_ids += [mid for mid, message in pycompat.items(message_values)
+ notified_ids += [mid for mid, message in message_values.items()
if message.get('model') == doc_model and message.get('res_id') in fol_mids]
# CRUD: Access rights related to the document
other_ids = other_ids.difference(set(notified_ids))
model_record_ids = _generate_model_record_ids(message_values, other_ids)
document_related_ids = []
- for model, doc_ids in pycompat.items(model_record_ids):
+ for model, doc_ids in model_record_ids.items():
DocumentModel = self.env[model]
mids = DocumentModel.browse(doc_ids).exists()
if hasattr(DocumentModel, 'check_mail_message_access'):
DocumentModel.check_mail_message_access(mids.ids, operation) # ?? mids ?
else:
self.env['mail.thread'].check_mail_message_access(mids.ids, operation, model_name=model)
- document_related_ids += [mid for mid, message in pycompat.items(message_values)
+ document_related_ids += [mid for mid, message in message_values.items()
if message.get('model') == model and message.get('res_id') in mids.ids]
# Calculate remaining ids: if not void, raise an error
diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py
index f3a7acb253b..1bd92aff430 100644
--- a/addons/mail/models/mail_template.py
+++ b/addons/mail/models/mail_template.py
@@ -379,7 +379,7 @@ class MailTemplate(models.Model):
'user': self.env.user,
'ctx': self._context, # context kw would clash with mako internals
}
- for res_id, record in pycompat.items(res_to_rec):
+ for res_id, record in res_to_rec.items():
variables['object'] = record
try:
render_result = template.render(variables)
@@ -391,7 +391,7 @@ class MailTemplate(models.Model):
results[res_id] = render_result
if post_process:
- for res_id, result in pycompat.items(results):
+ for res_id, result in results.items():
results[res_id] = self.render_post_process(result)
return multi_mode and results or results[res_ids[0]]
@@ -412,7 +412,7 @@ class MailTemplate(models.Model):
self.ensure_one()
langs = self.render_template(self.lang, self.model, res_ids)
- for res_id, lang in pycompat.items(langs):
+ for res_id, lang in langs.items():
if lang:
template = self.with_context(lang=lang)
else:
@@ -431,11 +431,11 @@ class MailTemplate(models.Model):
if self.use_default_to or self._context.get('tpl_force_default_to'):
default_recipients = self.env['mail.thread'].message_get_default_recipients(res_model=self.model, res_ids=res_ids)
- for res_id, recipients in pycompat.items(default_recipients):
+ for res_id, recipients in default_recipients.items():
results[res_id].pop('partner_to', None)
results[res_id].update(recipients)
- for res_id, values in pycompat.items(results):
+ for res_id, values in results.items():
partner_ids = values.get('partner_ids', list())
if self._context.get('tpl_partners_only'):
mails = tools.email_split(values.pop('email_to', '')) + tools.email_split(values.pop('email_cc', ''))
@@ -474,11 +474,11 @@ class MailTemplate(models.Model):
# templates: res_id -> template; template -> res_ids
templates_to_res_ids = {}
- for res_id, template in pycompat.items(res_ids_to_templates):
+ for res_id, template in res_ids_to_templates.items():
templates_to_res_ids.setdefault(template, []).append(res_id)
results = dict()
- for template, template_res_ids in pycompat.items(templates_to_res_ids):
+ for template, template_res_ids in templates_to_res_ids.items():
Template = self.env['mail.template']
# generate fields value for all res_ids linked to the current template
if template.lang:
@@ -488,7 +488,7 @@ class MailTemplate(models.Model):
generated_field_values = Template.render_template(
getattr(template, field), template.model, template_res_ids,
post_process=(field == 'body_html'))
- for res_id, field_value in pycompat.items(generated_field_values):
+ for res_id, field_value in generated_field_values.items():
results.setdefault(res_id, dict())[field] = field_value
# compute recipients
if any(field in fields for field in ['email_to', 'partner_to', 'email_cc']):
diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py
index 835fd42b5a6..296f79bed14 100644
--- a/addons/mail/models/mail_thread.py
+++ b/addons/mail/models/mail_thread.py
@@ -26,7 +26,6 @@ from werkzeug import url_encode
from odoo import _, api, exceptions, fields, models, tools
from odoo.tools import pycompat
-from odoo.tools.pycompat import text_type
from odoo.tools.safe_eval import safe_eval
@@ -239,7 +238,7 @@ class MailThread(models.AbstractModel):
# auto_subscribe: take values and defaults into account
create_values = dict(values)
- for key, val in pycompat.items(self._context):
+ for key, val in self._context.items():
if key.startswith('default_') and key[8:] not in create_values:
create_values[key[8:]] = val
thread.message_auto_subscribe(list(create_values), values=create_values)
@@ -389,7 +388,7 @@ class MailThread(models.AbstractModel):
always tracked fields and modified on_change fields
"""
tracked_fields = []
- for name, field in pycompat.items(self._fields):
+ for name, field in self._fields.items():
if getattr(field, 'track_visibility', False):
tracked_fields.append(name)
@@ -417,10 +416,10 @@ class MailThread(models.AbstractModel):
@api.multi
def _message_track_post_template(self, tracking):
- if not any(change for rec_id, (change, tracking_value_ids) in pycompat.items(tracking)):
+ if not any(change for rec_id, (change, tracking_value_ids) in tracking.items()):
return True
templates = self._track_template(tracking)
- for field_name, (template, post_kwargs) in pycompat.items(templates):
+ for field_name, (template, post_kwargs) in templates.items():
if not template:
continue
if isinstance(template, pycompat.string_types):
@@ -451,7 +450,7 @@ class MailThread(models.AbstractModel):
display_values_ids = []
# generate tracked_values data structure: {'col_name': {col_info, new_value, old_value}}
- for col_name, col_info in pycompat.items(tracked_fields):
+ for col_name, col_info in tracked_fields.items():
track_visibility = getattr(self._fields[col_name], 'track_visibility', 'onchange')
initial_value = initial[col_name]
new_value = getattr(self, col_name)
@@ -817,7 +816,7 @@ class MailThread(models.AbstractModel):
def message_capable_models(self):
""" Used by the plugin addon, based for plugin_outlook and others. """
ret_dict = {}
- for model_name, model in pycompat.items(self.env):
+ for model_name, model in self.env.items():
if hasattr(model, "message_process") and hasattr(model, "message_post"):
ret_dict[model_name] = model._description
return ret_dict
@@ -2057,7 +2056,7 @@ class MailThread(models.AbstractModel):
if auto_follow_fields is None:
auto_follow_fields = ['user_id']
user_field_lst = []
- for name, field in pycompat.items(self._fields):
+ for name, field in self._fields.items():
if name in auto_follow_fields and name in updated_fields and getattr(field, 'track_visibility', False) and field.comodel_name == 'res.users':
user_field_lst.append(name)
return user_field_lst
@@ -2153,10 +2152,10 @@ class MailThread(models.AbstractModel):
for partner in to_add_users.mapped('partner_id'):
new_partners.setdefault(partner.id, None)
- for pid, subtypes in pycompat.items(new_partners):
+ for pid, subtypes in new_partners.items():
subtypes = list(subtypes) if subtypes is not None else None
self.message_subscribe(partner_ids=[pid], subtype_ids=subtypes, force=(subtypes != None))
- for cid, subtypes in pycompat.items(new_channels):
+ for cid, subtypes in new_channels.items():
subtypes = list(subtypes) if subtypes is not None else None
self.message_subscribe(channel_ids=[cid], subtype_ids=subtypes, force=(subtypes != None))
diff --git a/addons/mail/models/res_partner.py b/addons/mail/models/res_partner.py
index 6379ddb8c42..9140959f89e 100644
--- a/addons/mail/models/res_partner.py
+++ b/addons/mail/models/res_partner.py
@@ -4,7 +4,6 @@
import logging
import threading
-from odoo.tools import pycompat
from odoo.tools.misc import split_every
from odoo import _, api, fields, models, registry, SUPERUSER_ID
@@ -175,7 +174,7 @@ class Partner(models.Model):
emails = self.env['mail.mail']
recipients_nbr, recipients_max = 0, 50
- for email_type, recipient_template_values in pycompat.items(recipients):
+ for email_type, recipient_template_values in recipients.items():
if recipient_template_values['followers']:
# generate notification email content
template_fol_values = dict(base_template_ctx, **recipient_template_values) # fixme: set button_unfollow to none
diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py
index 76412ce041c..767462df892 100644
--- a/addons/mail/wizard/mail_compose_message.py
+++ b/addons/mail/wizard/mail_compose_message.py
@@ -140,7 +140,7 @@ class MailComposer(models.TransientModel):
for mid, rmod, rid in self._cr.fetchall():
message_values[mid] = {'model': rmod, 'res_id': rid}
# remove from the set to check the ids that mail_compose_message accepts
- author_ids = [mid for mid, message in pycompat.items(message_values)
+ author_ids = [mid for mid, message in message_values.items()
if message.get('model') and not message.get('res_id')]
self = self.browse(list(set(self.ids) - set(author_ids))) # not sure slef = ...
@@ -248,7 +248,7 @@ class MailComposer(models.TransientModel):
for res_ids in sliced_res_ids:
batch_mails = Mail
all_mail_values = wizard.get_mail_values(res_ids)
- for res_id, mail_values in pycompat.items(all_mail_values):
+ for res_id, mail_values in all_mail_values.items():
if wizard.composition_mode == 'mass_mail':
batch_mails |= Mail.create(mail_values)
else:
@@ -338,7 +338,7 @@ class MailComposer(models.TransientModel):
def onchange_template_id_wrapper(self):
self.ensure_one()
values = self.onchange_template_id(self.template_id.id, self.composition_mode, self.model, self.res_id)['value']
- for fname, value in pycompat.items(values):
+ for fname, value in values.items():
setattr(self, fname, value)
@api.multi
diff --git a/addons/marketing_campaign/models/marketing_campaign.py b/addons/marketing_campaign/models/marketing_campaign.py
index 7370633114e..6fea98870d8 100644
--- a/addons/marketing_campaign/models/marketing_campaign.py
+++ b/addons/marketing_campaign/models/marketing_campaign.py
@@ -9,7 +9,6 @@ import re
from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError
-from odoo.tools import pycompat
from odoo.tools.safe_eval import safe_eval
from odoo.addons import decimal_precision as dp
@@ -466,7 +465,7 @@ class MarketingCampaignWorkitem(models.Model):
matching_workitems = []
for id, res_id, model in res:
workitem_map.setdefault(model, {}).setdefault(res_id, set()).add(id)
- for model, id_map in pycompat.items(workitem_map):
+ for model, id_map in workitem_map.items():
Model = self.env[model]
condition_name[0] = Model._rec_name
condition = [('id', 'in', list(id_map)), condition_name]
diff --git a/addons/mrp/models/mrp_workcenter.py b/addons/mrp/models/mrp_workcenter.py
index 58226b2e9e8..cc12ec0060b 100644
--- a/addons/mrp/models/mrp_workcenter.py
+++ b/addons/mrp/models/mrp_workcenter.py
@@ -5,7 +5,6 @@ from dateutil import relativedelta
import datetime
from odoo import api, exceptions, fields, models, _
-from odoo.tools import pycompat
class MrpWorkcenter(models.Model):
@@ -74,7 +73,7 @@ class MrpWorkcenter(models.Model):
if res_group['state'] in ('pending', 'ready', 'progress'):
result_duration_expected[res_group['workcenter_id'][0]] += res_group['duration_expected']
for workcenter in self:
- workcenter.workorder_count = sum(count for state, count in pycompat.items(result[workcenter.id]) if state not in ('done', 'cancel'))
+ workcenter.workorder_count = sum(count for state, count in result[workcenter.id].items() if state not in ('done', 'cancel'))
workcenter.workorder_pending_count = result[workcenter.id].get('pending', 0)
workcenter.workcenter_load = result_duration_expected[workcenter.id]
workcenter.workorder_ready_count = result[workcenter.id].get('ready', 0)
diff --git a/addons/mrp_repair/wizard/mrp_repair_make_invoice.py b/addons/mrp_repair/wizard/mrp_repair_make_invoice.py
index a659e45e962..03e89da5cd5 100644
--- a/addons/mrp_repair/wizard/mrp_repair_make_invoice.py
+++ b/addons/mrp_repair/wizard/mrp_repair_make_invoice.py
@@ -2,7 +2,6 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
-from odoo.tools import pycompat
class MakeInvoice(models.TransientModel):
@@ -25,7 +24,7 @@ class MakeInvoice(models.TransientModel):
# but that second call will not do anything, since the repairs are already invoiced.
repairs.action_repair_invoice_create()
return {
- 'domain': [('id', 'in', list(pycompat.values(new_invoice)))],
+ 'domain': [('id', 'in', list(new_invoice.values()))],
'name': 'Invoices',
'view_type': 'form',
'view_mode': 'tree,form',
diff --git a/addons/pad/models/pad.py b/addons/pad/models/pad.py
index 945e24f4308..d0c2055c739 100644
--- a/addons/pad/models/pad.py
+++ b/addons/pad/models/pad.py
@@ -10,7 +10,7 @@ import requests
from odoo import api, models, _
from odoo.exceptions import UserError
-from odoo.tools import html2plaintext, pycompat
+from odoo.tools import html2plaintext
from ..py_etherpad import EtherpadLiteClient
@@ -106,7 +106,7 @@ class PadCommon(models.AbstractModel):
# In case the pad is created programmatically, the content is not filled in yet since it is
# normally initialized by the JS layer
- for k, field in pycompat.items(self._fields):
+ for k, field in self._fields.items():
if hasattr(field, 'pad_content_field') and k not in vals:
ctx = {
'model': self._name,
@@ -121,7 +121,7 @@ class PadCommon(models.AbstractModel):
def _set_pad_value(self, vals):
# Update the pad if the `pad_content_field` is modified
- for k, field in pycompat.items(self._fields):
+ for k, field in self._fields.items():
if hasattr(field, 'pad_content_field') and vals.get(field.pad_content_field) and self[k]:
company = self.env.user.sudo().company_id
myPad = EtherpadLiteClient(company.pad_key, company.pad_server + '/api')
@@ -129,7 +129,7 @@ class PadCommon(models.AbstractModel):
myPad.setText(path, (html2plaintext(vals[field.pad_content_field]).encode('utf-8')))
# Update the `pad_content_field` if the pad is modified
- for k, v in list(pycompat.items(vals)):
+ for k, v in vals.items():
field = self._fields[k]
if hasattr(field, 'pad_content_field'):
vals[field.pad_content_field] = self.pad_get_content(v)
@@ -139,7 +139,7 @@ class PadCommon(models.AbstractModel):
self.ensure_one()
if not default:
default = {}
- for k, field in pycompat.items(self._fields):
+ for k, field in self._fields.items():
if hasattr(field, 'pad_content_field'):
pad = self.pad_generate_url()
default[k] = pad.get('url')
diff --git a/addons/payment/models/payment_acquirer.py b/addons/payment/models/payment_acquirer.py
index 909536ac95c..2e36d891344 100644
--- a/addons/payment/models/payment_acquirer.py
+++ b/addons/payment/models/payment_acquirer.py
@@ -5,7 +5,7 @@ import logging
import datetime
from odoo import api, exceptions, fields, models, _
-from odoo.tools import consteq, float_round, image_resize_images, ustr, pycompat
+from odoo.tools import consteq, float_round, image_resize_images, ustr
from odoo.addons.base.module import module
from odoo.exceptions import ValidationError
@@ -169,7 +169,7 @@ class PaymentAcquirer(models.Model):
""" If the field has 'required_if_provider=""' attribute, then it
required if record.provider is . """
for acquirer in self:
- if any(getattr(f, 'required_if_provider', None) == acquirer.provider and not acquirer[k] for k, f in pycompat.items(self._fields)):
+ if any(getattr(f, 'required_if_provider', None) == acquirer.provider and not acquirer[k] for k, f in self._fields.items()):
return False
return True
diff --git a/addons/payment_adyen/models/payment.py b/addons/payment_adyen/models/payment.py
index 787160fd1ea..dbc24ced0c0 100644
--- a/addons/payment_adyen/models/payment.py
+++ b/addons/payment_adyen/models/payment.py
@@ -15,8 +15,6 @@ from odoo import api, fields, models, tools, _
from odoo.addons.payment.models.payment_acquirer import ValidationError
from odoo.addons.payment_adyen.controllers.main import AdyenController
-from odoo.tools import pycompat
-
_logger = logging.getLogger(__name__)
@@ -52,7 +50,7 @@ class AcquirerAdyen(models.Model):
def signParams(parms):
signing_string = ':'.join(
escapeVal(v)
- for v in chain(pycompat.keys(parms), pycompat.values(parms))
+ for v in chain(parms.keys(), parms.values())
)
hm = hmac.new(hmac_key, signing_string.encode('utf-8'), hashlib.sha256)
return base64.b64encode(hm.digest())
@@ -81,7 +79,7 @@ class AcquirerAdyen(models.Model):
hmac_key = binascii.a2b_hex(self.adyen_skin_hmac_key.encode('ascii'))
raw_values = {k: values.get(k.encode('ascii'), '') for k in keys if k in values}
- raw_values_ordered = OrderedDict(sorted(pycompat.items(raw_values), key=lambda t: t[0]))
+ raw_values_ordered = OrderedDict(sorted(raw_values.items(), key=lambda t: t[0]))
return signParams(raw_values_ordered)
diff --git a/addons/payment_authorize/tests/test_authorize.py b/addons/payment_authorize/tests/test_authorize.py
index 6d3f4244583..59fb401b091 100644
--- a/addons/payment_authorize/tests/test_authorize.py
+++ b/addons/payment_authorize/tests/test_authorize.py
@@ -11,7 +11,7 @@ import odoo
from odoo.addons.payment.models.payment_acquirer import ValidationError
from odoo.addons.payment.tests.common import PaymentAcquirerCommon
from odoo.addons.payment_authorize.controllers.main import AuthorizeController
-from odoo.tools import mute_logger, pycompat
+from odoo.tools import mute_logger
@odoo.tests.common.at_install(True)
@@ -91,7 +91,7 @@ class AuthorizeForm(AuthorizeCommon):
tree = objectify.fromstring(res)
self.assertEqual(tree.get('action'), 'https://test.authorize.net/gateway/transact.dll', 'Authorize: wrong form POST url')
for el in tree.iterfind('input'):
- values = list(pycompat.values(el.attrib))
+ values = list(el.attrib.values())
if values[1] in ['submit', 'x_fp_hash', 'return_url', 'x_state', 'x_ship_to_state']:
continue
self.assertEqual(
diff --git a/addons/payment_buckaroo/controllers/main.py b/addons/payment_buckaroo/controllers/main.py
index 5af6a454b47..40e4ae539e4 100644
--- a/addons/payment_buckaroo/controllers/main.py
+++ b/addons/payment_buckaroo/controllers/main.py
@@ -6,7 +6,6 @@ import werkzeug
from odoo import http
from odoo.http import request
-from odoo.tools import pycompat
_logger = logging.getLogger(__name__)
@@ -27,6 +26,6 @@ class BuckarooController(http.Controller):
""" Buckaroo."""
_logger.info('Buckaroo: entering form_feedback with post data %s', pprint.pformat(post)) # debug
request.env['payment.transaction'].sudo().form_feedback(post, 'buckaroo')
- post = {key.upper(): value for key, value in pycompat.items(post)}
+ post = {key.upper(): value for key, value in post.items()}
return_url = post.get('ADD_RETURNDATA') or '/'
return werkzeug.utils.redirect(return_url)
diff --git a/addons/payment_buckaroo/models/payment.py b/addons/payment_buckaroo/models/payment.py
index a07ca83318d..ec0cadfab01 100644
--- a/addons/payment_buckaroo/models/payment.py
+++ b/addons/payment_buckaroo/models/payment.py
@@ -8,7 +8,6 @@ from odoo import api, fields, models, _
from odoo.addons.payment.models.payment_acquirer import ValidationError
from odoo.addons.payment_buckaroo.controllers.main import BuckarooController
-from odoo.tools import pycompat
from odoo.tools.float_utils import float_compare
_logger = logging.getLogger(__name__)
@@ -21,7 +20,7 @@ def normalize_keys_upper(data):
convert everything to upper case to be able to easily detected the presence
of a parameter by checking the uppercase key only
"""
- return {key.upper(): val for key, val in pycompat.items(data)}
+ return {key.upper(): val for key, val in data.items()}
class AcquirerBuckaroo(models.Model):
@@ -73,7 +72,7 @@ class AcquirerBuckaroo(models.Model):
del values[key]
break
- items = sorted(pycompat.items(values), key=lambda pair: pair[0].lower())
+ items = sorted(values.items(), key=lambda pair: pair[0].lower())
sign = ''.join('%s=%s' % (k, urls.url_unquote_plus(v)) for k, v in items)
else:
sign = ''.join('%s=%s' % (k, get_value(k)) for k in keys)
diff --git a/addons/payment_ogone/models/payment.py b/addons/payment_ogone/models/payment.py
index a5ae46bdcd3..7a2adf37d45 100644
--- a/addons/payment_ogone/models/payment.py
+++ b/addons/payment_ogone/models/payment.py
@@ -15,7 +15,7 @@ from odoo import api, fields, models, _
from odoo.addons.payment.models.payment_acquirer import ValidationError
from odoo.addons.payment_ogone.controllers.main import OgoneController
from odoo.addons.payment_ogone.data import ogone
-from odoo.tools import float_round, DEFAULT_SERVER_DATE_FORMAT, pycompat
+from odoo.tools import float_round, DEFAULT_SERVER_DATE_FORMAT
from odoo.tools.float_utils import float_compare, float_repr
from odoo.tools.safe_eval import safe_eval
@@ -142,7 +142,7 @@ class PaymentAcquirerOgone(models.Model):
]
return key.upper() in keys
- items = sorted((k.upper(), v) for k, v in pycompat.items(values))
+ items = sorted((k.upper(), v) for k, v in values.items())
sign = ''.join('%s=%s%s' % (k, v, key) for k, v in items if v and filter_key(k))
sign = sign.encode("utf-8")
shasign = sha1(sign).hexdigest()
diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py
index 5e059a41cfc..9e730f9a2e5 100644
--- a/addons/point_of_sale/models/pos_order.py
+++ b/addons/point_of_sale/models/pos_order.py
@@ -8,7 +8,7 @@ import psycopg2
import pytz
from odoo import api, fields, models, tools, _
-from odoo.tools import float_is_zero, pycompat
+from odoo.tools import float_is_zero
from odoo.exceptions import UserError
from odoo.http import request
from odoo.addons import decimal_precision as dp
@@ -333,7 +333,7 @@ class PosOrder(models.Model):
# round tax lines per order
if rounding_method == 'round_globally':
- for group_key, group_value in pycompat.items(grouped_data):
+ for group_key, group_value in grouped_data.items():
if group_key[0] == 'tax':
for line in group_value:
line['credit'] = cur.round(line['credit'])
@@ -351,7 +351,7 @@ class PosOrder(models.Model):
order.write({'state': 'done', 'account_move': move.id})
all_lines = []
- for group_key, group_data in pycompat.items(grouped_data):
+ for group_key, group_data in grouped_data.items():
for value in group_data:
all_lines.append((0, 0, value),)
if move: # In case no order was changed
@@ -1032,7 +1032,7 @@ class ReportSaleDetails(models.AbstractModel):
'total_paid': user_currency.round(total),
'payments': payments,
'company_name': self.env.user.company_id.name,
- 'taxes': list(pycompat.values(taxes)),
+ 'taxes': list(taxes.values()),
'products': sorted([{
'product_id': product.id,
'product_name': product.name,
@@ -1041,7 +1041,7 @@ class ReportSaleDetails(models.AbstractModel):
'price_unit': price_unit,
'discount': discount,
'uom': product.uom_id.name
- } for (product, price_unit, discount), qty in pycompat.items(products_sold)], key=lambda l: l['product_name'])
+ } for (product, price_unit, discount), qty in products_sold.items()], key=lambda l: l['product_name'])
}
@api.multi
diff --git a/addons/product/models/product_pricelist.py b/addons/product/models/product_pricelist.py
index a0457f021ba..392447809f4 100644
--- a/addons/product/models/product_pricelist.py
+++ b/addons/product/models/product_pricelist.py
@@ -90,7 +90,7 @@ class Pricelist(models.Model):
results = {}
for pricelist in pricelists:
subres = pricelist._compute_price_rule(products_qty_partner, date=date, uom_id=uom_id)
- for product_id, price in pycompat.items(subres):
+ for product_id, price in subres.items():
results.setdefault(product_id, {})
results[product_id][pricelist.id] = price
return results
@@ -254,11 +254,11 @@ class Pricelist(models.Model):
self.ensure_one()
return {
product_id: res_tuple[0]
- for product_id, res_tuple in pycompat.items(self._compute_price_rule(
+ for product_id, res_tuple in self._compute_price_rule(
list(pycompat.izip(products, quantities, partners)),
date=date,
uom_id=uom_id
- ))
+ ).items()
}
def get_product_price(self, product, quantity, partner, date=False, uom_id=False):
@@ -280,7 +280,7 @@ class Pricelist(models.Model):
@api.multi
def price_get(self, prod_id, qty, partner=None):
""" Multi pricelist, mono product - returns price per pricelist """
- return {key: price[0] for key, price in pycompat.items(self.price_rule_get(prod_id, qty, partner=partner))}
+ return {key: price[0] for key, price in self.price_rule_get(prod_id, qty, partner=partner).items()}
@api.multi
def price_rule_get_multi(self, products_by_qty_by_partner):
diff --git a/addons/product_expiry/models/production_lot.py b/addons/product_expiry/models/production_lot.py
index 89d2a7569ff..6be9a2865dd 100644
--- a/addons/product_expiry/models/production_lot.py
+++ b/addons/product_expiry/models/production_lot.py
@@ -2,7 +2,6 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import datetime
from odoo import api, fields, models
-from odoo.tools import pycompat
class StockProductionLot(models.Model):
@@ -54,5 +53,5 @@ class StockProductionLot(models.Model):
@api.onchange('product_id')
def _onchange_product(self):
dates_dict = self._get_dates()
- for field, value in pycompat.items(dates_dict):
+ for field, value in dates_dict.items():
setattr(self, field, value)
diff --git a/addons/product_margin/models/product_product.py b/addons/product_margin/models/product_product.py
index f203a9e146b..3dd735b26a4 100644
--- a/addons/product_margin/models/product_product.py
+++ b/addons/product_margin/models/product_product.py
@@ -4,7 +4,6 @@
import time
from odoo import api, fields, models
-from odoo.tools import pycompat
class ProductProduct(models.Model):
@@ -139,6 +138,6 @@ class ProductProduct(models.Model):
res[val.id]['expected_margin'] = res[val.id]['sale_expected'] - res[val.id]['normal_cost']
res[val.id]['total_margin_rate'] = res[val.id]['turnover'] and res[val.id]['total_margin'] * 100 / res[val.id]['turnover'] or 0.0
res[val.id]['expected_margin_rate'] = res[val.id]['sale_expected'] and res[val.id]['expected_margin'] * 100 / res[val.id]['sale_expected'] or 0.0
- for k, v in pycompat.items(res[val.id]):
+ for k, v in res[val.id].items():
setattr(val, k, v)
return res
diff --git a/addons/rating/models/rating.py b/addons/rating/models/rating.py
index a5b54afb3ac..f4bd17b48f3 100644
--- a/addons/rating/models/rating.py
+++ b/addons/rating/models/rating.py
@@ -6,7 +6,6 @@ import uuid
from odoo import api, fields, models, tools, _
from odoo.modules.module import get_resource_path
-from odoo.tools import pycompat
RATING_LIMIT_SATISFIED = 7
RATING_LIMIT_OK = 3
@@ -275,7 +274,7 @@ class RatingMixin(models.AbstractModel):
values.update((d['rating'], d['rating_count']) for d in data)
# add other stats
if add_stats:
- rating_number = sum(pycompat.values(values))
+ rating_number = sum(values.values())
result = {
'repartition': values,
'avg': sum(float(key * values[key]) for key in values) / rating_number if rating_number > 0 else 0,
diff --git a/addons/rating_project/models/project.py b/addons/rating_project/models/project.py
index 915c97848ec..8a4f86d3b96 100644
--- a/addons/rating_project/models/project.py
+++ b/addons/rating_project/models/project.py
@@ -3,7 +3,6 @@
from datetime import timedelta
-from odoo.tools import pycompat
from odoo import api, fields, models, _
from odoo.tools.safe_eval import safe_eval
@@ -80,13 +79,13 @@ class Project(models.Model):
domain = [('create_date', '>=', fields.Datetime.to_string(fields.datetime.now() - timedelta(days=30)))]
for project in self:
activity = project.tasks.rating_get_grades(domain)
- project.percentage_satisfaction_project = activity['great'] * 100 / sum(pycompat.values(activity)) if sum(pycompat.values(activity)) else -1
+ project.percentage_satisfaction_project = activity['great'] * 100 / sum(activity.values()) if sum(activity.values()) else -1
@api.one
@api.depends('tasks.rating_ids.rating')
def _compute_percentage_satisfaction_task(self):
activity = self.tasks.rating_get_grades()
- self.percentage_satisfaction_task = activity['great'] * 100 / sum(pycompat.values(activity)) if sum(pycompat.values(activity)) else -1
+ self.percentage_satisfaction_task = activity['great'] * 100 / sum(activity.values()) if sum(activity.values()) else -1
percentage_satisfaction_task = fields.Integer(
compute='_compute_percentage_satisfaction_task', string="Happy % on Task", store=True, default=-1)
diff --git a/addons/rating_project_issue/models/project_issue.py b/addons/rating_project_issue/models/project_issue.py
index 8116c0f50f1..cd3d541d1ef 100644
--- a/addons/rating_project_issue/models/project_issue.py
+++ b/addons/rating_project_issue/models/project_issue.py
@@ -4,7 +4,6 @@
from datetime import timedelta
from odoo import api, fields, models
-from odoo.tools import pycompat
from odoo.tools.safe_eval import safe_eval
@@ -63,11 +62,11 @@ class Project(models.Model):
if project.use_tasks:
activity_task = project.tasks.rating_get_grades(domain)
activity_great = activity_task['great']
- activity_sum = sum(pycompat.values(activity_task))
+ activity_sum = sum(activity_task.values())
if project.use_issues:
activity_issue = self.env['project.issue'].search([('project_id', '=', project.id)]).rating_get_grades(domain)
activity_great += activity_issue['great']
- activity_sum += sum(pycompat.values(activity_issue))
+ activity_sum += sum(activity_issue.values())
project.percentage_satisfaction_project = activity_great * 100 / activity_sum if activity_sum else -1
@api.one
@@ -75,7 +74,7 @@ class Project(models.Model):
def _compute_percentage_satisfaction_issue(self):
project_issue = self.env['project.issue'].search([('project_id', '=', self.id)])
activity = project_issue.rating_get_grades()
- self.percentage_satisfaction_issue = activity['great'] * 100 / sum(pycompat.values(activity)) if sum(pycompat.values(activity)) else -1
+ self.percentage_satisfaction_issue = activity['great'] * 100 / sum(activity.values()) if sum(activity.values()) else -1
percentage_satisfaction_issue = fields.Integer(compute='_compute_percentage_satisfaction_issue', string="Happy % on Issue", store=True, default=-1)
diff --git a/addons/sale/models/account_invoice.py b/addons/sale/models/account_invoice.py
index 5163f4baa6c..c4ad56d1277 100644
--- a/addons/sale/models/account_invoice.py
+++ b/addons/sale/models/account_invoice.py
@@ -3,7 +3,6 @@
from itertools import groupby
from odoo import api, fields, models, _
-from odoo.tools import pycompat
class AccountInvoice(models.Model):
@@ -58,7 +57,7 @@ class AccountInvoice(models.Model):
result = super(AccountInvoice, self)._refund_cleanup_lines(lines)
if self.env.context.get('mode') == 'modify':
for i, line in enumerate(lines):
- for name, field in pycompat.items(line._fields):
+ for name, field in line._fields.items():
if name == 'sale_line_ids':
result[i][2][name] = [(6, 0, line[name].ids)]
line[name] = False
diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py
index 7e554c6af08..8fe5623e339 100644
--- a/addons/sale/models/sale.py
+++ b/addons/sale/models/sale.py
@@ -8,7 +8,7 @@ from datetime import datetime, timedelta
from odoo import api, fields, models, _
from odoo.exceptions import UserError
-from odoo.tools import float_is_zero, float_compare, DEFAULT_SERVER_DATETIME_FORMAT, pycompat
+from odoo.tools import float_is_zero, float_compare, DEFAULT_SERVER_DATETIME_FORMAT
from odoo.tools.misc import formatLang
from odoo.addons import decimal_precision as dp
@@ -400,7 +400,7 @@ class SaleOrder(models.Model):
if not invoices:
raise UserError(_('There is no invoicable line.'))
- for invoice in pycompat.values(invoices):
+ for invoice in invoices.values():
if not invoice.invoice_line_ids:
raise UserError(_('There is no invoicable line.'))
# If invoice is negative, do a refund invoice instead
@@ -417,7 +417,7 @@ class SaleOrder(models.Model):
invoice.message_post_with_view('mail.message_origin_link',
values={'self': invoice, 'origin': references[invoice]},
subtype_id=self.env.ref('mail.mt_note').id)
- return [inv.id for inv in pycompat.values(invoices)]
+ return [inv.id for inv in invoices.values()]
@api.multi
def action_draft(self):
@@ -557,7 +557,7 @@ class SaleOrder(models.Model):
if tax.include_base_amount:
base_tax += tax.compute_all(price_reduce + base_tax, quantity=1, product=line.product_id,
partner=self.partner_shipping_id)['taxes'][0]['amount']
- res = sorted(pycompat.items(res), key=lambda l: l[0].sequence)
+ res = sorted(res.items(), key=lambda l: l[0].sequence)
res = [(l[0].name, l[1]) for l in res]
return res
diff --git a/addons/sale/models/sale_analytic.py b/addons/sale/models/sale_analytic.py
index 733bd74bc2a..96f2f896f44 100644
--- a/addons/sale/models/sale_analytic.py
+++ b/addons/sale/models/sale_analytic.py
@@ -3,7 +3,6 @@
from odoo import api, fields, models, _
from odoo.exceptions import UserError
-from odoo.tools import pycompat
class SaleOrderLine(models.Model):
@@ -41,7 +40,7 @@ class SaleOrderLine(models.Model):
qty = d['unit_amount']
lines[line] += qty
- for line, qty in pycompat.items(lines):
+ for line, qty in lines.items():
line.qty_delivered = qty
return True
diff --git a/addons/sale/tests/test_sale_order.py b/addons/sale/tests/test_sale_order.py
index 84dbee6a3fd..2b6c082b150 100644
--- a/addons/sale/tests/test_sale_order.py
+++ b/addons/sale/tests/test_sale_order.py
@@ -2,7 +2,6 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.exceptions import UserError, AccessError
-from odoo.tools import pycompat
from .test_sale_common import TestSale
@@ -18,10 +17,10 @@ class TestSaleOrder(TestSale):
'partner_id': self.partner.id,
'partner_invoice_id': self.partner.id,
'partner_shipping_id': self.partner.id,
- 'order_line': [(0, 0, {'name': p.name, 'product_id': p.id, 'product_uom_qty': 2, 'product_uom': p.uom_id.id, 'price_unit': p.list_price}) for (_, p) in pycompat.items(self.products)],
+ 'order_line': [(0, 0, {'name': p.name, 'product_id': p.id, 'product_uom_qty': 2, 'product_uom': p.uom_id.id, 'price_unit': p.list_price}) for p in self.products.values()],
'pricelist_id': self.env.ref('product.list0').id,
})
- self.assertEqual(so.amount_total, sum([2 * p.list_price for (k, p) in pycompat.items(self.products)]), 'Sale: total amount is wrong')
+ self.assertEqual(so.amount_total, sum([2 * p.list_price for p in self.products.values()]), 'Sale: total amount is wrong')
# send quotation
so.force_quotation_send()
@@ -36,7 +35,7 @@ class TestSaleOrder(TestSale):
inv_id = so.action_invoice_create()
inv = inv_obj.browse(inv_id)
self.assertEqual(len(inv.invoice_line_ids), 2, 'Sale: invoice is missing lines')
- self.assertEqual(inv.amount_total, sum([2 * p.list_price if p.invoice_policy == 'order' else 0 for (k, p) in pycompat.items(self.products)]), 'Sale: invoice total amount is wrong')
+ self.assertEqual(inv.amount_total, sum([2 * p.list_price if p.invoice_policy == 'order' else 0 for p in self.products.values()]), 'Sale: invoice total amount is wrong')
self.assertTrue(so.invoice_status == 'no', 'Sale: SO status after invoicing should be "nothing to invoice"')
self.assertTrue(len(so.invoice_ids) == 1, 'Sale: invoice is missing')
@@ -47,7 +46,7 @@ class TestSaleOrder(TestSale):
inv_id = so.action_invoice_create()
inv = inv_obj.browse(inv_id)
self.assertEqual(len(inv.invoice_line_ids), 2, 'Sale: second invoice is missing lines')
- self.assertEqual(inv.amount_total, sum([2 * p.list_price if p.invoice_policy == 'delivery' else 0 for (k, p) in pycompat.items(self.products)]), 'Sale: second invoice total amount is wrong')
+ self.assertEqual(inv.amount_total, sum([2 * p.list_price if p.invoice_policy == 'delivery' else 0 for p in self.products.values()]), 'Sale: second invoice total amount is wrong')
self.assertTrue(so.invoice_status == 'invoiced', 'Sale: SO status after invoicing everything should be "invoiced"')
self.assertTrue(len(so.invoice_ids) == 2, 'Sale: invoice is missing')
# go over the sold quantity
@@ -72,7 +71,7 @@ class TestSaleOrder(TestSale):
'partner_id': self.partner.id,
'partner_invoice_id': self.partner.id,
'partner_shipping_id': self.partner.id,
- 'order_line': [(0, 0, {'name': p.name, 'product_id': p.id, 'product_uom_qty': 2, 'product_uom': p.uom_id.id, 'price_unit': p.list_price}) for (_, p) in pycompat.items(self.products)],
+ 'order_line': [(0, 0, {'name': p.name, 'product_id': p.id, 'product_uom_qty': 2, 'product_uom': p.uom_id.id, 'price_unit': p.list_price}) for p in self.products.values()],
'pricelist_id': self.env.ref('product.list0').id,
})
diff --git a/addons/sale_stock/tests/test_sale_stock.py b/addons/sale_stock/tests/test_sale_stock.py
index 5a4755d2c16..3dd6d5103ca 100644
--- a/addons/sale_stock/tests/test_sale_stock.py
+++ b/addons/sale_stock/tests/test_sale_stock.py
@@ -3,7 +3,6 @@
from odoo.addons.sale.tests.test_sale_common import TestSale
from odoo.exceptions import UserError
-from odoo.tools import pycompat
class TestSaleStock(TestSale):
@@ -17,7 +16,7 @@ class TestSaleStock(TestSale):
'partner_id': self.partner.id,
'partner_invoice_id': self.partner.id,
'partner_shipping_id': self.partner.id,
- 'order_line': [(0, 0, {'name': p.name, 'product_id': p.id, 'product_uom_qty': 2, 'product_uom': p.uom_id.id, 'price_unit': p.list_price}) for (_, p) in pycompat.items(self.products)],
+ 'order_line': [(0, 0, {'name': p.name, 'product_id': p.id, 'product_uom_qty': 2, 'product_uom': p.uom_id.id, 'price_unit': p.list_price}) for p in self.products.values()],
'pricelist_id': self.env.ref('product.list0').id,
'picking_policy': 'direct',
})
@@ -74,7 +73,7 @@ class TestSaleStock(TestSale):
'partner_id': self.partner.id,
'partner_invoice_id': self.partner.id,
'partner_shipping_id': self.partner.id,
- 'order_line': [(0, 0, {'name': p.name, 'product_id': p.id, 'product_uom_qty': 2, 'product_uom': p.uom_id.id, 'price_unit': p.list_price}) for (_, p) in pycompat.items(self.products)],
+ 'order_line': [(0, 0, {'name': p.name, 'product_id': p.id, 'product_uom_qty': 2, 'product_uom': p.uom_id.id, 'price_unit': p.list_price}) for p in self.products.values()],
'pricelist_id': self.env.ref('product.list0').id,
'picking_policy': 'direct',
})
diff --git a/addons/stock/models/procurement.py b/addons/stock/models/procurement.py
index 8ac7fc638d7..8d5e419fb90 100644
--- a/addons/stock/models/procurement.py
+++ b/addons/stock/models/procurement.py
@@ -9,8 +9,7 @@ from psycopg2 import OperationalError
from odoo import api, fields, models, registry, _
from odoo.osv import expression
-from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, float_compare, \
- float_round, pycompat
+from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, float_compare, float_round
import logging
@@ -311,7 +310,7 @@ class ProcurementOrder(models.Model):
location_data[key]['orderpoints'] += orderpoint
location_data[key]['groups'] = self._procurement_from_orderpoint_get_groups([orderpoint.id])
- for location_id, location_data in pycompat.items(location_data):
+ for location_id, location_data in location_data.items():
location_orderpoints = location_data['orderpoints']
product_context = dict(self._context, location=location_orderpoints[0].location_id.id)
substract_quantity = location_orderpoints.subtract_procurements_from_orderpoints()
diff --git a/addons/stock/models/stock_inventory.py b/addons/stock/models/stock_inventory.py
index 866f3e2104c..bb14b839d32 100644
--- a/addons/stock/models/stock_inventory.py
+++ b/addons/stock/models/stock_inventory.py
@@ -4,7 +4,7 @@
from odoo import api, fields, models, _
from odoo.addons import decimal_precision as dp
from odoo.exceptions import UserError
-from odoo.tools import float_utils, pycompat
+from odoo.tools import float_utils
class Inventory(models.Model):
@@ -251,7 +251,7 @@ class Inventory(models.Model):
for product_data in self.env.cr.dictfetchall():
# replace the None the dictionary by False, because falsy values are tested later on
- for void_field in [item[0] for item in pycompat.items(product_data) if item[1] is None]:
+ for void_field in [item[0] for item in product_data.items() if item[1] is None]:
product_data[void_field] = False
product_data['theoretical_qty'] = product_data['product_qty']
if product_data['product_id']:
diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py
index 5eab237011e..6b7b74f5143 100644
--- a/addons/stock/models/stock_move.py
+++ b/addons/stock/models/stock_move.py
@@ -10,7 +10,7 @@ from odoo import api, fields, models, _
from odoo.addons import decimal_precision as dp
from odoo.addons.procurement.models import procurement
from odoo.exceptions import UserError
-from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, pycompat
+from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
from odoo.tools.float_utils import float_compare, float_round, float_is_zero
@@ -595,7 +595,7 @@ class StockMove(models.Model):
(move_waiting | move_create_proc).write({'state': 'waiting'})
# assign picking in batch for all confirmed move that share the same details
- for key, moves in pycompat.items(to_assign):
+ for moves in to_assign.values():
moves.assign_picking()
self._push_apply()
return self
diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py
index 536ac2a5e6d..de736ef0bcf 100644
--- a/addons/stock/models/stock_picking.py
+++ b/addons/stock/models/stock_picking.py
@@ -7,7 +7,7 @@ import time
from itertools import groupby
from odoo import api, fields, models, _
-from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, pycompat
+from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
from odoo.tools.float_utils import float_compare, float_round
from odoo.addons.procurement.models import procurement
from odoo.exceptions import UserError
@@ -665,7 +665,7 @@ class Picking(models.Model):
self.ensure_one()
moves = self.env['stock.move']
for move_line in self.move_line_ids:
- for product, remaining_qty in pycompat.items(move_line._get_remaining_prod_quantities()):
+ for product, remaining_qty in move_line._get_remaining_prod_quantities().items():
if float_compare(remaining_qty, 0, precision_rounding=product.uom_id.rounding) > 0:
vals = self._prepare_values_extra_move(move_line, product, remaining_qty)
moves |= moves.create(vals)
diff --git a/addons/stock/models/stock_quant.py b/addons/stock/models/stock_quant.py
index 5609f5be6a6..f2ebb9d0c87 100644
--- a/addons/stock/models/stock_quant.py
+++ b/addons/stock/models/stock_quant.py
@@ -5,7 +5,6 @@ from psycopg2 import OperationalError
from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError
-from odoo.tools import pycompat
from odoo.osv import expression
@@ -274,7 +273,7 @@ class QuantPackage(models.Model):
@api.multi
def name_get(self):
- return list(pycompat.items(self._compute_complete_name()))
+ return list(self._compute_complete_name().items())
def _compute_complete_name(self):
""" Forms complete name of location from parent location to child location. """
diff --git a/addons/stock/models/stock_warehouse.py b/addons/stock/models/stock_warehouse.py
index 1f7e44f23ea..d8bd64253c6 100644
--- a/addons/stock/models/stock_warehouse.py
+++ b/addons/stock/models/stock_warehouse.py
@@ -8,7 +8,7 @@ from dateutil import relativedelta
from odoo import api, fields, models, _
from odoo.addons import decimal_precision as dp
from odoo.exceptions import UserError, ValidationError
-from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, pycompat
+from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
import logging
@@ -99,7 +99,7 @@ class Warehouse(models.Model):
'wh_output_stock_loc_id': {'name': _('Output'), 'active': delivery_steps != 'ship_only', 'usage': 'internal'},
'wh_pack_stock_loc_id': {'name': _('Packing Zone'), 'active': delivery_steps == 'pick_pack_ship', 'usage': 'internal'},
}
- for field_name, values in pycompat.items(sub_locations):
+ for field_name, values in sub_locations.items():
values['location_id'] = vals['view_location_id']
if vals.get('company_id'):
values['company_id'] = vals.get('company_id')
@@ -240,10 +240,10 @@ class Warehouse(models.Model):
},
}
data = self._get_picking_type_values(self.reception_steps, self.delivery_steps, self.wh_pack_stock_loc_id)
- for field_name, values in pycompat.items(data):
+ for field_name in data:
data[field_name].update(create_data[field_name])
- for picking_type, values in pycompat.items(data):
+ for picking_type, values in data.items():
sequence = IrSequenceSudo.create(sequence_data[picking_type])
values.update(warehouse_id=self.id, color=color, sequence_id=sequence.id)
warehouse_data[picking_type] = PickingType.create(values).id
@@ -598,8 +598,8 @@ class Warehouse(models.Model):
@api.one
def _update_picking_type(self):
picking_type_values = self._get_picking_type_values(self.reception_steps, self.delivery_steps, self.wh_pack_stock_loc_id)
- for field_name, values in pycompat.items(picking_type_values):
- getattr(self, field_name).write(values)
+ for field_name, values in picking_type_values.items():
+ self[field_name].write(values)
@api.multi
def _update_name_and_code(self, new_name=False, new_code=False):
diff --git a/addons/stock/wizard/make_procurement.py b/addons/stock/wizard/make_procurement.py
index 369995e7a15..2fa3db75b5d 100644
--- a/addons/stock/wizard/make_procurement.py
+++ b/addons/stock/wizard/make_procurement.py
@@ -2,7 +2,6 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
-from odoo.tools import pycompat
class MakeProcurement(models.TransientModel):
@@ -51,8 +50,8 @@ class MakeProcurement(models.TransientModel):
@api.onchange('product_id')
def onchange_product_id(self):
if self.product_id:
- for key, value in pycompat.items(self.onchange_product_id_dict(self.product_id.id)):
- setattr(self, key, value)
+ for key, value in self.onchange_product_id_dict(self.product_id.id).items():
+ self[key] = value
@api.model
def create(self, values):
diff --git a/addons/stock_landed_costs/models/stock_landed_cost.py b/addons/stock_landed_costs/models/stock_landed_cost.py
index aeb6e42366f..5fd5ce8f63b 100644
--- a/addons/stock_landed_costs/models/stock_landed_cost.py
+++ b/addons/stock_landed_costs/models/stock_landed_cost.py
@@ -7,7 +7,6 @@ from odoo import api, fields, models, tools, _
from odoo.addons import decimal_precision as dp
from odoo.addons.stock_landed_costs.models import product
from odoo.exceptions import UserError
-from odoo.tools import pycompat
class StockMove(models.Model):
@@ -123,7 +122,7 @@ class LandedCost(models.Model):
for val_line in landed_cost.valuation_adjustment_lines:
val_to_cost_lines[val_line.cost_line_id] += val_line.additional_landed_cost
if any(tools.float_compare(cost_line.price_unit, val_amount, precision_digits=prec_digits) != 0
- for cost_line, val_amount in pycompat.items(val_to_cost_lines)):
+ for cost_line, val_amount in val_to_cost_lines.items()):
return False
return True
@@ -204,9 +203,8 @@ class LandedCost(models.Model):
towrite_dict[valuation.id] = value
else:
towrite_dict[valuation.id] += value
- if towrite_dict:
- for key, value in pycompat.items(towrite_dict):
- AdjustementLines.browse(key).write({'additional_landed_cost': value})
+ for key, value in towrite_dict.items():
+ AdjustementLines.browse(key).write({'additional_landed_cost': value})
return True
diff --git a/addons/survey/models/survey.py b/addons/survey/models/survey.py
index 84692c63f9d..7bcf53f67ab 100644
--- a/addons/survey/models/survey.py
+++ b/addons/survey/models/survey.py
@@ -15,8 +15,6 @@ from odoo.exceptions import UserError, ValidationError
from odoo.addons.website.models.website import slug
-from odoo.tools import pycompat
-
email_validator = re.compile(r"[^@]+@[^@]+\.[^@]+")
_logger = logging.getLogger(__name__)
@@ -26,7 +24,7 @@ def dict_keys_startswith(dictionary, string):
.. note::
This function uses dictionary comprehensions (Python >= 2.7)
"""
- return {k: v for k, v in pycompat.items(dictionary) if k.startswith(string)}
+ return {k: v for k, v in dictionary.items() if k.startswith(string)}
class SurveyStage(models.Model):
@@ -240,7 +238,7 @@ class Survey(models.Model):
answers[input_line.value_suggested.id]['count'] += 1
if input_line.answer_type == 'text' and (not(current_filters) or input_line.user_input_id.id in current_filters):
comments.append(input_line)
- result_summary = {'answers': list(pycompat.values(answers)), 'comments': comments}
+ result_summary = {'answers': list(answers.values()), 'comments': comments}
# Calculate and return statistics for matrix
if question.type == 'matrix':
@@ -640,7 +638,7 @@ class SurveyQuestion(models.Model):
if self.comments_allowed:
comment_answer = answer_candidates.pop(("%s_%s" % (answer_tag, 'comment')), '').strip()
# Preventing answers with blank value
- if all(not answer.strip() for answer in pycompat.values(answer_candidates)) and answer_candidates:
+ if all(not answer.strip() for answer in answer_candidates.values()) and answer_candidates:
errors.update({answer_tag: self.constr_error_msg})
# There is no answer neither comments (if comments count as answer)
if not answer_candidates and self.comment_count_as_answer and (not comment_flag or not comment_answer):
diff --git a/addons/survey/tests/test_survey.py b/addons/survey/tests/test_survey.py
index 04a65a02562..b5f9897438b 100644
--- a/addons/survey/tests/test_survey.py
+++ b/addons/survey/tests/test_survey.py
@@ -13,8 +13,6 @@ from odoo.exceptions import UserError
from odoo.tests.common import TransactionCase
from odoo.addons.website.models.website import slug
-from odoo.tools import pycompat
-
class TestSurvey(TransactionCase):
@@ -179,7 +177,7 @@ class TestSurvey(TransactionCase):
base_url = self.env['ir.config_parameter'].get_param('web.base.url')
urltypes = {'public': 'start', 'print': 'print', 'result': 'results'}
- for urltype, urltxt in pycompat.items(urltypes):
+ for urltype, urltxt in urltypes.items():
survey_url = getattr(self.survey1, urltype + '_url')
survey_url_relative = getattr(self.survey1.with_context({'relative_url': True}), urltype + '_url')
self.assertTrue(validate_url(survey_url))
@@ -211,8 +209,8 @@ class TestSurvey(TransactionCase):
answers = [input_portal.user_input_line_ids[0], input_public.user_input_line_ids[0]]
expected_values = {'answer_type': 'free_text', 'value_free_text': "Test Answer"}
for answer in answers:
- for field, value in pycompat.items(expected_values):
- self.assertEqual(getattr(answer, field), value, msg="Unable to answer the survey. Expected behaviour of %s is not proper." % (field))
+ for field, value in expected_values.items():
+ self.assertEqual(answer[field], value, msg="Unable to answer the survey. Expected behaviour of %s is not proper." % (field))
def test_10_survey_result_simple_multiple_choice(self):
question = self.env['survey.question'].sudo(self.survey_manager).create({
@@ -265,7 +263,7 @@ class TestSurvey(TransactionCase):
'print': {'method': 'print', 'token': '/test', 'text': 'Print'},
'result': {'method': 'result', 'token': '', 'text': 'Results of the'},
'test': {'method': 'public', 'token': '/phantom', 'text': 'Results of the'}}
- for action, val in pycompat.items(actions):
+ for action, val in actions.items():
result = getattr(self.survey1.with_context({'survey_token': val['token'][1:]}), 'action_' + action + '_survey')()
url = getattr(self.survey1.with_context({'relative_url': True}), val['method'] + '_url') + val['token']
self.assertEqual(result['url'], url)
diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py
index 114d7ba2e4e..abf019371dc 100644
--- a/addons/web/controllers/main.py
+++ b/addons/web/controllers/main.py
@@ -963,7 +963,7 @@ class Binary(http.Controller):
def force_contenttype(self, headers, contenttype='image/png'):
dictheaders = dict(headers)
dictheaders['Content-Type'] = contenttype
- return list(pycompat.items(dictheaders))
+ return list(dictheaders.items())
@http.route(['/web/content',
'/web/content/',
@@ -1216,7 +1216,7 @@ class Export(http.Controller):
else:
fields['.id'] = fields.pop('id', {'string': 'ID'})
- fields_sequence = sorted(pycompat.items(fields),
+ fields_sequence = sorted(fields.items(),
key=lambda field: odoo.tools.ustr(field[1].get('string', '')))
records = []
@@ -1227,7 +1227,7 @@ class Export(http.Controller):
if field.get('readonly'):
# If none of the field's states unsets readonly, skip the field
if all(dict(attrs).get('readonly', True)
- for attrs in pycompat.values(field.get('states', {}))):
+ for attrs in field.get('states', {}).values()):
continue
if not field.get('exportable', True):
continue
@@ -1319,7 +1319,7 @@ class Export(http.Controller):
export_fields = [field.split('/', 1)[1] for field in fields]
return (
(prefix + '/' + k, prefix_string + '/' + v)
- for k, v in pycompat.items(self.fields_info(model, export_fields)))
+ for k, v in self.fields_info(model, export_fields).items())
class ExportFormat(object):
raw_data = False
diff --git a/addons/web_diagram/controllers/main.py b/addons/web_diagram/controllers/main.py
index 56b6c76eefe..d29b60df40e 100644
--- a/addons/web_diagram/controllers/main.py
+++ b/addons/web_diagram/controllers/main.py
@@ -2,7 +2,6 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import odoo.http as http
-from odoo.tools import pycompat
from odoo.tools.safe_eval import safe_eval
@@ -46,7 +45,7 @@ class DiagramView(http.Controller):
isolate_nodes[blnk_node['id']] = blnk_node
y = [
t['y']
- for t in pycompat.values(nodes)
+ for t in nodes.values()
if t['x'] == 20
if t['y']
]
@@ -99,11 +98,11 @@ class DiagramView(http.Controller):
color='white',
options={}
)
- for color, expr in pycompat.items(bgcolors):
+ for color, expr in bgcolors.items():
if safe_eval(expr, act):
n['color'] = color
- for shape, expr in pycompat.items(shapes):
+ for shape, expr in shapes.items():
if safe_eval(expr, act):
n['shape'] = shape
diff --git a/addons/web_editor/models/ir_ui_view.py b/addons/web_editor/models/ir_ui_view.py
index 96c27bc923d..977f02f4b44 100644
--- a/addons/web_editor/models/ir_ui_view.py
+++ b/addons/web_editor/models/ir_ui_view.py
@@ -91,7 +91,7 @@ class IrUiView(models.Model):
@api.model
def to_field_ref(self, el):
# filter out meta-information inserted in the document
- attributes = {k: v for k, v in pycompat.items(el.attrib)
+ attributes = {k: v for k, v in el.attrib.items()
if not k.startswith('data-oe-')}
attributes['t-field'] = el.get('data-oe-expression')
diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py
index 20e2320b68a..ef8245598a1 100644
--- a/addons/website/controllers/main.py
+++ b/addons/website/controllers/main.py
@@ -38,11 +38,11 @@ class QueryURL(object):
def __call__(self, path=None, path_args=None, **kw):
path = path or self.path
- for key, value in pycompat.items(self.args):
+ for key, value in self.args.items():
kw.setdefault(key, value)
path_args = OrderedSet(path_args or []) | self.path_args
paths, fragments = {}, []
- for key, value in pycompat.items(kw):
+ for key, value in kw.items():
if value and key in path_args:
if isinstance(value, models.BaseModel):
paths[key] = slug(value)
diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py
index c06ff77de90..133d0928caa 100644
--- a/addons/website/models/ir_http.py
+++ b/addons/website/models/ir_http.py
@@ -14,7 +14,7 @@ import odoo
from odoo import api, models
from odoo import SUPERUSER_ID
from odoo.http import request
-from odoo.tools import config, pycompat
+from odoo.tools import config
from odoo.exceptions import QWebException
from odoo.tools.safe_eval import safe_eval
@@ -244,7 +244,7 @@ class Http(models.AbstractModel):
def _postprocess_args(cls, arguments, rule):
super(Http, cls)._postprocess_args(arguments, rule)
- for key, val in pycompat.items(arguments):
+ for key, val in arguments.items():
# Replace uid placeholder by the current request.uid
if isinstance(val, models.BaseModel) and isinstance(val._uid, RequestUID):
arguments[key] = val.sudo(request.uid)
diff --git a/addons/website/models/ir_qweb.py b/addons/website/models/ir_qweb.py
index e6cedfe07d2..a20db972c0b 100644
--- a/addons/website/models/ir_qweb.py
+++ b/addons/website/models/ir_qweb.py
@@ -5,7 +5,6 @@ import ast
from odoo import models
from odoo.http import request
-from odoo.tools import pycompat
class QWeb(models.AbstractModel):
@@ -82,7 +81,7 @@ class QWeb(models.AbstractModel):
atts = super(QWeb, self)._get_dynamic_att(tagName, atts, options, values)
if options.get('rendering_bundle'):
return atts
- for name, value in pycompat.items(atts):
+ for name, value in atts.items():
atts[name] = self._website_build_attribute(tagName, name, value, options, values)
return atts
diff --git a/addons/website/models/website.py b/addons/website/models/website.py
index 77be240cfbe..55f44887f03 100644
--- a/addons/website/models/website.py
+++ b/addons/website/models/website.py
@@ -363,7 +363,7 @@ class Website(models.Model):
def get_url_localized(router, lang):
arguments = dict(request.endpoint_arguments)
- for key, val in list(pycompat.items(arguments)):
+ for key, val in list(arguments.items()):
if isinstance(val, models.BaseModel):
arguments[key] = val.with_context(lang=lang)
return router.build(request.endpoint, arguments)
@@ -496,7 +496,7 @@ class Website(models.Model):
endpoint = rule.endpoint
methods = endpoint.routing.get('methods') or ['GET']
- converters = list(pycompat.values(rule._converters))
+ converters = list(rule._converters.values())
if not ('GET' in methods
and endpoint.routing['type'] == 'http'
and endpoint.routing['auth'] in ('none', 'public')
@@ -541,7 +541,7 @@ class Website(models.Model):
values = [{}]
# converters with a domain are processed after the other ones
convitems = sorted(
- pycompat.items(converters),
+ converters.items(),
key=lambda x: hasattr(x[1], 'domain') and (x[1].domain != '[]'))
for (i, (name, converter)) in enumerate(convitems):
newval = []
@@ -557,7 +557,7 @@ class Website(models.Model):
for value in values:
domain_part, url = rule.build(value, append_unknown=False)
page = {'loc': url}
- for key, val in pycompat.items(value):
+ for key, val in value.items():
if key.startswith('__'):
page[key[2:]] = val
if url in ('/sitemap.xml',):
diff --git a/addons/website/tests/test_converter.py b/addons/website/tests/test_converter.py
index 9267826c689..311c035bbac 100644
--- a/addons/website/tests/test_converter.py
+++ b/addons/website/tests/test_converter.py
@@ -4,8 +4,6 @@
import unittest
from odoo.addons.website.models.website import slugify, unslug
-from odoo.tools import pycompat
-
class TestUnslug(unittest.TestCase):
@@ -25,7 +23,7 @@ class TestUnslug(unittest.TestCase):
'foo1': (None, None),
}
- for slug, expected in pycompat.items(tests):
+ for slug, expected in tests.items():
self.assertEqual(unslug(slug), expected)
diff --git a/addons/website/tests/test_views.py b/addons/website/tests/test_views.py
index af9d362cfb9..7293eae4c56 100644
--- a/addons/website/tests/test_views.py
+++ b/addons/website/tests/test_views.py
@@ -11,11 +11,10 @@ from lxml import etree as ET, html
from lxml.html import builder as h
from odoo.tests import common
-from odoo.tools import pycompat
def attrs(**kwargs):
- return {'data-oe-%s' % key: str(value) for key, value in pycompat.items(kwargs)}
+ return {'data-oe-%s' % key: str(value) for key, value in kwargs.items()}
class TestViewSaving(common.TransactionCase):
diff --git a/addons/website_crm_partner_assign/controllers/main.py b/addons/website_crm_partner_assign/controllers/main.py
index 3c18c7cf470..6e300e66cd0 100644
--- a/addons/website_crm_partner_assign/controllers/main.py
+++ b/addons/website_crm_partner_assign/controllers/main.py
@@ -13,7 +13,6 @@ from odoo.http import request
from odoo.addons.website.models.website import slug, unslug
from odoo.addons.website_partner.controllers.main import WebsitePartnerPage
-from odoo.tools import pycompat
from odoo.tools.translate import _
from odoo.addons.website_portal.controllers.main import website_account
@@ -151,7 +150,7 @@ class WebsiteAccount(website_account):
'pager': pager,
'searchbar_sortings': searchbar_sortings,
'sortby': sortby,
- 'searchbar_filters': OrderedDict(sorted(pycompat.items(searchbar_filters))),
+ 'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())),
'filterby': filterby,
})
return request.render("website_crm_partner_assign.portal_my_opportunities", values)
diff --git a/addons/website_crm_partner_assign/models/crm_lead.py b/addons/website_crm_partner_assign/models/crm_lead.py
index f1f002d5dd0..b73be955c42 100644
--- a/addons/website_crm_partner_assign/models/crm_lead.py
+++ b/addons/website_crm_partner_assign/models/crm_lead.py
@@ -5,7 +5,6 @@ import random
from odoo.addons.base_geolocalize.models.res_partner import geo_find, geo_query_address
from odoo import api, fields, models, _
-from odoo.tools import pycompat
class CrmLead(models.Model):
@@ -45,7 +44,7 @@ class CrmLead(models.Model):
if lead.partner_assigned_id and lead.partner_assigned_id.user_id != lead.user_id:
salesmans_leads.setdefault(lead.partner_assigned_id.user_id.id, []).append(lead.id)
- for salesman_id, leads_ids in pycompat.items(salesmans_leads):
+ for salesman_id, leads_ids in salesmans_leads.items():
leads = self.browse(leads_ids)
leads.write({'user_id': salesman_id})
diff --git a/addons/website_crm_partner_assign/wizard/crm_forward_to_partner.py b/addons/website_crm_partner_assign/wizard/crm_forward_to_partner.py
index cb2fbf3ba03..5aa8073192f 100644
--- a/addons/website_crm_partner_assign/wizard/crm_forward_to_partner.py
+++ b/addons/website_crm_partner_assign/wizard/crm_forward_to_partner.py
@@ -3,7 +3,6 @@
from odoo import api, fields, models, _
from odoo.exceptions import UserError
-from odoo.tools import pycompat
class CrmLeadForwardToPartner(models.TransientModel):
@@ -86,7 +85,7 @@ class CrmLeadForwardToPartner(models.TransientModel):
else:
partners_leads[partner.id] = {'partner': partner, 'leads': [lead_details]}
- for partner_id, partner_leads in pycompat.items(partners_leads):
+ for partner_id, partner_leads in partners_leads.items():
in_portal = False
if portal_group:
for contact in (partner.child_ids or partner).filtered(lambda contact: contact.user_ids):
diff --git a/addons/website_event/controllers/main.py b/addons/website_event/controllers/main.py
index cd020a74372..5aed9a25ffa 100644
--- a/addons/website_event/controllers/main.py
+++ b/addons/website_event/controllers/main.py
@@ -9,7 +9,6 @@ from dateutil.relativedelta import relativedelta
from odoo import fields, http, _
from odoo.addons.website.models.website import slug
from odoo.http import request
-from odoo.tools import pycompat
class WebsiteEventController(http.Controller):
@@ -80,7 +79,7 @@ class WebsiteEventController(http.Controller):
def dom_without(without):
domain = [('state', "in", ['draft', 'confirm', 'done'])]
- for key, search in pycompat.items(domain_search):
+ for key, search in domain_search.items():
if key != without:
domain += search
return domain
@@ -234,16 +233,16 @@ class WebsiteEventController(http.Controller):
''' Process data posted from the attendee details form. '''
registrations = {}
global_values = {}
- for key, value in pycompat.items(details):
+ for key, value in details.items():
counter, field_name = key.split('-', 1)
if counter == '0':
global_values[field_name] = value
else:
registrations.setdefault(counter, dict())[field_name] = value
- for key, value in pycompat.items(global_values):
- for registration in pycompat.values(registrations):
+ for key, value in global_values.items():
+ for registration in registrations.values():
registration[key] = value
- return list(pycompat.values(registrations))
+ return list(registrations.values())
@http.route(['/event//registration/confirm'], type='http', auth="public", methods=['POST'], website=True)
def registration_confirm(self, event, **post):
diff --git a/addons/website_event_questions/controllers/main.py b/addons/website_event_questions/controllers/main.py
index e709e0b3d06..684999a26ff 100644
--- a/addons/website_event_questions/controllers/main.py
+++ b/addons/website_event_questions/controllers/main.py
@@ -3,8 +3,6 @@
from odoo.addons.website_event.controllers.main import WebsiteEventController
-from odoo.tools import pycompat
-
class WebsiteEvent(WebsiteEventController):
@@ -13,7 +11,7 @@ class WebsiteEvent(WebsiteEventController):
registrations = super(WebsiteEvent, self)._process_registration_details(details)
for registration in registrations:
answer_ids = []
- for key, value in pycompat.items(registration):
+ for key, value in registration.items():
if key.startswith('answer_ids-'):
answer_ids.append([4, int(value)])
registration['answer_ids'] = answer_ids
diff --git a/addons/website_event_sale/controllers/main.py b/addons/website_event_sale/controllers/main.py
index 324fa1026ed..7ccb7f9e4b5 100644
--- a/addons/website_event_sale/controllers/main.py
+++ b/addons/website_event_sale/controllers/main.py
@@ -4,7 +4,6 @@
from odoo import http, _
from odoo.addons.website_event.controllers.main import WebsiteEventController
from odoo.http import request
-from odoo.tools import pycompat
class WebsiteEventSaleController(WebsiteEventController):
@@ -16,7 +15,7 @@ class WebsiteEventSaleController(WebsiteEventController):
def _process_tickets_details(self, data):
ticket_post = {}
- for key, value in pycompat.items(data):
+ for key, value in data.items():
if not key.startswith('nb_register') or '-' not in key:
continue
items = key.split('-')
diff --git a/addons/website_event_track/controllers/main.py b/addons/website_event_track/controllers/main.py
index 1864b28379c..f11aa0bea13 100644
--- a/addons/website_event_track/controllers/main.py
+++ b/addons/website_event_track/controllers/main.py
@@ -8,7 +8,7 @@ import pytz
from odoo import fields, http
from odoo.http import request
-from odoo.tools import html_escape as escape, html2plaintext, pycompat
+from odoo.tools import html_escape as escape, html2plaintext
class WebsiteEventTrackController(http.Controller):
@@ -75,7 +75,7 @@ class WebsiteEventTrackController(http.Controller):
days = {}
tracks_by_days = {}
- for day, tracks in pycompat.items(days_tracks):
+ for day, tracks in days_tracks.items():
tracks_by_days[day] = tracks
days[day] = self._prepare_calendar(event, tracks)
diff --git a/addons/website_form/controllers/main.py b/addons/website_form/controllers/main.py
index cdf1034c7a9..978692e894a 100644
--- a/addons/website_form/controllers/main.py
+++ b/addons/website_form/controllers/main.py
@@ -10,7 +10,7 @@ from psycopg2 import IntegrityError
from odoo import http
from odoo.http import request
-from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT, pycompat
+from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
from odoo.tools.translate import _
from odoo.exceptions import ValidationError
from odoo.addons.base.ir.ir_qweb.fields import nl2br
@@ -118,7 +118,7 @@ class WebsiteForm(http.Controller):
error_fields = []
- for field_name, field_value in pycompat.items(values):
+ for field_name, field_value in values.items():
# If the value of the field if a file
if hasattr(field_value, 'filename'):
# Undo file upload field name indexing
@@ -164,7 +164,7 @@ class WebsiteForm(http.Controller):
if hasattr(dest_model, "website_form_input_filter"):
data['record'] = dest_model.website_form_input_filter(request, data['record'])
- missing_required_fields = [label for label, field in pycompat.items(authorized_fields) if field['required'] and not label in data['record']]
+ missing_required_fields = [label for label, field in authorized_fields.items() if field['required'] and not label in data['record']]
if any(error_fields):
raise ValidationError(error_fields + missing_required_fields)
diff --git a/addons/website_form/models/models.py b/addons/website_form/models/models.py
index 654fbfa9ee4..67364d59dc2 100644
--- a/addons/website_form/models/models.py
+++ b/addons/website_form/models/models.py
@@ -5,7 +5,6 @@ import itertools
from odoo import models, fields, api
from odoo.http import request
-from odoo.tools import pycompat
class website_form_config(models.Model):
@@ -42,7 +41,7 @@ class website_form_model(models.Model):
])
}
return {
- k: v for k, v in pycompat.items(self.get_authorized_fields(self.model))
+ k: v for k, v in self.get_authorized_fields(self.model).items()
if k in included
}
@@ -52,7 +51,7 @@ class website_form_model(models.Model):
model = self.env[model_name]
fields_get = model.fields_get()
- for key, val in pycompat.items(model._inherits):
+ for key, val in model._inherits.items():
fields_get.pop(val, None)
# Unrequire fields with default values
diff --git a/addons/website_livechat/controllers/main.py b/addons/website_livechat/controllers/main.py
index 675b56e561f..753e4eef1ae 100644
--- a/addons/website_livechat/controllers/main.py
+++ b/addons/website_livechat/controllers/main.py
@@ -3,7 +3,6 @@
from odoo import http
from odoo.http import request
-from odoo.tools import pycompat
class WebsiteLivechat(http.Controller):
@@ -27,7 +26,7 @@ class WebsiteLivechat(http.Controller):
# compute percentage
percentage = dict.fromkeys(['great', 'okay', 'bad'], 0)
for grade in repartition:
- percentage[grade] = repartition[grade] * 100 / sum(pycompat.values(repartition)) if sum(pycompat.values(repartition)) else 0
+ percentage[grade] = repartition[grade] * 100 / sum(repartition.values()) if sum(repartition.values()) else 0
# the value dict to render the template
values = {
diff --git a/addons/website_portal/controllers/main.py b/addons/website_portal/controllers/main.py
index 3b2fbfc2a2d..865312cc7c6 100644
--- a/addons/website_portal/controllers/main.py
+++ b/addons/website_portal/controllers/main.py
@@ -4,7 +4,6 @@
from odoo import http
from odoo.http import request
from odoo import tools
-from odoo.tools import pycompat
from odoo.tools.translate import _
from odoo.exceptions import ValidationError
@@ -134,7 +133,7 @@ class website_account(http.Controller):
error["vat"] = 'error'
# error message for empty required fields
- if [err for err in pycompat.values(error) if err == 'missing']:
+ if [err for err in error.values() if err == 'missing']:
error_message.append(_('Some required fields are empty.'))
unknown = [k for k in data if k not in self.MANDATORY_BILLING_FIELDS + self.OPTIONAL_BILLING_FIELDS]
diff --git a/addons/website_portal_purchase/controllers/website_portal.py b/addons/website_portal_purchase/controllers/website_portal.py
index 874c311f92a..4d8762e4346 100644
--- a/addons/website_portal_purchase/controllers/website_portal.py
+++ b/addons/website_portal_purchase/controllers/website_portal.py
@@ -6,7 +6,6 @@ from collections import OrderedDict
from odoo import http
from odoo.exceptions import AccessError
from odoo.http import request
-from odoo.tools import pycompat
from odoo.tools.translate import _
from odoo.addons.website_portal.controllers.main import website_account, get_records_pager
@@ -89,7 +88,7 @@ class WebsitePortal(website_account):
'archive_groups': archive_groups,
'searchbar_sortings': searchbar_sortings,
'sortby': sortby,
- 'searchbar_filters': OrderedDict(sorted(pycompat.items(searchbar_filters))),
+ 'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())),
'filterby': filterby,
'default_url': '/my/purchase',
})
diff --git a/addons/website_project/controllers/main.py b/addons/website_project/controllers/main.py
index d8716efd9ac..720c4f65700 100644
--- a/addons/website_project/controllers/main.py
+++ b/addons/website_project/controllers/main.py
@@ -8,7 +8,6 @@ from odoo.http import request
from odoo.addons.website_portal.controllers.main import website_account, get_records_pager
from odoo.osv.expression import OR
-from odoo.tools import pycompat
class WebsiteAccount(website_account):
@@ -156,7 +155,7 @@ class WebsiteAccount(website_account):
'searchbar_inputs': searchbar_inputs,
'search_in': search_in,
'sortby': sortby,
- 'searchbar_filters': OrderedDict(sorted(pycompat.items(searchbar_filters))),
+ 'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())),
'filterby': filterby,
})
return request.render("website_project.my_tasks", values)
diff --git a/addons/website_project_issue/controllers/main.py b/addons/website_project_issue/controllers/main.py
index 1ce21cff8e8..940544a2188 100644
--- a/addons/website_project_issue/controllers/main.py
+++ b/addons/website_project_issue/controllers/main.py
@@ -105,7 +105,7 @@ class WebsiteAccount(website_account):
'searchbar_sortings': searchbar_sortings,
'searchbar_inputs': searchbar_inputs,
'sortby': sortby,
- 'searchbar_filters': OrderedDict(sorted(pycompat.items(searchbar_filters))),
+ 'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())),
'filterby': filterby,
'search_in': search_in,
'search': search,
diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py
index 51462df1de7..40057484efe 100644
--- a/addons/website_sale/controllers/main.py
+++ b/addons/website_sale/controllers/main.py
@@ -12,8 +12,6 @@ from odoo.addons.website.controllers.main import QueryURL
from odoo.exceptions import ValidationError
from odoo.addons.website_form.controllers.main import WebsiteForm
-from odoo.tools import pycompat
-
_logger = logging.getLogger(__name__)
PPG = 20 # Products Per Page
@@ -78,10 +76,10 @@ class TableCompute(object):
index += 1
# Format table according to HTML needs
- rows = sorted(pycompat.items(self.table))
+ rows = sorted(self.table.items())
rows = [r[1] for r in rows]
for col in range(len(rows)):
- cols = sorted(pycompat.items(rows[col]))
+ cols = sorted(rows[col].items())
x += len(cols)
rows[col] = [r[1] for r in cols if r[1]]
@@ -373,7 +371,7 @@ class WebsiteSale(http.Controller):
return request.redirect("/shop/cart")
def _filter_attributes(self, **kw):
- return {k: v for k, v in pycompat.items(kw) if "attribute" in k}
+ return {k: v for k, v in kw.items() if "attribute" in k}
@http.route(['/shop/cart/update_json'], type='json', auth="public", methods=['POST'], website=True, csrf=False)
def cart_update_json(self, product_id, line_id=None, add_qty=None, set_qty=None, display=True):
@@ -491,7 +489,7 @@ class WebsiteSale(http.Controller):
except ValidationError:
error["vat"] = 'error'
- if [err for err in pycompat.items(error) if err == 'missing']:
+ if [err for err in error.items() if err == 'missing']:
error_message.append(_('Some required fields are empty.'))
return error, error_message
@@ -517,7 +515,7 @@ class WebsiteSale(http.Controller):
def values_postprocess(self, order, mode, values, errors, error_msg):
new_values = {}
authorized_fields = request.env['ir.model']._get('res.partner')._get_form_writable_fields()
- for k, v in pycompat.items(values):
+ for k, v in values.items():
# don't drop empty value, it could be a field to reset
if k in authorized_fields and v is not None:
new_values[k] = v
@@ -680,7 +678,7 @@ class WebsiteSale(http.Controller):
# if form posted
if 'post_values' in post:
values = {}
- for field_name, field_value in pycompat.items(post):
+ for field_name, field_value in post.items():
if field_name in request.env['sale.order']._fields and field_name.startswith('x_'):
values[field_name] = field_value
if values:
diff --git a/addons/website_sale/models/sale_order.py b/addons/website_sale/models/sale_order.py
index cffff7f2f3d..724d24b5c03 100644
--- a/addons/website_sale/models/sale_order.py
+++ b/addons/website_sale/models/sale_order.py
@@ -6,7 +6,6 @@ import random
from odoo import api, models, fields, _
from odoo.http import request
from odoo.exceptions import UserError, ValidationError
-from odoo.tools import pycompat
_logger = logging.getLogger(__name__)
@@ -93,7 +92,7 @@ class SaleOrder(models.Model):
# add untracked attributes in the name
untracked_attributes = []
- for k, v in pycompat.items(attributes):
+ for k, v in attributes.items():
# attribute should be like 'attribute-48-1' where 48 is the product_id, 1 is the attribute_id and v is the attribute value
attribute_value = self.env['product.attribute.value'].sudo().browse(int(v))
if attribute_value and not attribute_value.attribute_id.create_variant:
diff --git a/addons/website_sale/tests/test_website_sale_pricelist.py b/addons/website_sale/tests/test_website_sale_pricelist.py
index cf97fd815cc..21accb52814 100644
--- a/addons/website_sale/tests/test_website_sale_pricelist.py
+++ b/addons/website_sale/tests/test_website_sale_pricelist.py
@@ -2,7 +2,6 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from mock import patch
from odoo.tests.common import TransactionCase
-from odoo.tools import pycompat
class TestWebsitePriceList(TransactionCase):
@@ -61,7 +60,7 @@ class TestWebsitePriceList(TransactionCase):
'CA': ['Canada'],
'US': ['USD', 'EUR', 'Benelux', 'Canada']
}
- for country, result in pycompat.items(country_list):
+ for country, result in country_list.items():
pls = self.get_pl(show, current_pl, country)
self.assertEquals(len(set(pls.mapped('name')) & set(result)), len(pls), 'Test failed for %s (%s %s vs %s %s)'
% (country, len(pls), pls.mapped('name'), len(result), result))
@@ -78,7 +77,7 @@ class TestWebsitePriceList(TransactionCase):
'CA': ['Canada']
}
- for country, result in pycompat.items(country_list):
+ for country, result in country_list.items():
pls = self.get_pl(show, current_pl, country)
self.assertEquals(len(set(pls.mapped('name')) & set(result)), len(pls), 'Test failed for %s (%s %s vs %s %s)'
% (country, len(pls), pls.mapped('name'), len(result), result))
@@ -99,7 +98,7 @@ class TestWebsitePriceList(TransactionCase):
'CA': False
}
- for country, result in pycompat.items(country_list):
+ for country, result in country_list.items():
self.args['country'] = country
# mock patch method could not pass env context
available = self.website.is_pricelist_available(christmas_pl)
@@ -120,7 +119,7 @@ class TestWebsitePriceList(TransactionCase):
'CA': ['EUR', 'Canada'],
'US': ['USD', 'EUR', 'Benelux', 'Canada']
}
- for country, result in pycompat.items(country_list):
+ for country, result in country_list.items():
pls = self.get_pl(show, current_pl, country)
self.assertEquals(len(set(pls.mapped('name')) & set(result)), len(pls), 'Test failed for %s (%s %s vs %s %s)'
% (country, len(pls), pls.mapped('name'), len(result), result))
diff --git a/addons/website_sale_options/controllers/main.py b/addons/website_sale_options/controllers/main.py
index 8349f0e08bc..af48c17f2e1 100644
--- a/addons/website_sale_options/controllers/main.py
+++ b/addons/website_sale_options/controllers/main.py
@@ -5,8 +5,6 @@ from odoo import http
from odoo.http import request
from odoo.addons.website_sale.controllers.main import WebsiteSale
-from odoo.tools import pycompat
-
class WebsiteSaleOptions(WebsiteSale):
@@ -26,7 +24,7 @@ class WebsiteSaleOptions(WebsiteSale):
option_ids = product.optional_product_ids.mapped('product_variant_ids').ids
optional_product_ids = []
- for k, v in pycompat.items(kw):
+ for k, v in kw.items():
if "optional-product-" in k and int(kw.get(k.replace("product", "add"))) and int(v) in option_ids:
optional_product_ids.append(int(v))
diff --git a/addons/website_slides/models/slides.py b/addons/website_slides/models/slides.py
index a4de9105a1c..ad5df26cadd 100644
--- a/addons/website_slides/models/slides.py
+++ b/addons/website_slides/models/slides.py
@@ -12,7 +12,7 @@ import re
from werkzeug import urls
from odoo import api, fields, models, SUPERUSER_ID, _
-from odoo.tools import image, pycompat
+from odoo.tools import image
from odoo.tools.translate import html_translate
from odoo.exceptions import Warning
from odoo.addons.website.models.website import slug
@@ -323,8 +323,8 @@ class Slide(models.Model):
values = res['values']
if not values.get('document_id'):
raise Warning(_('Please enter valid Youtube or Google Doc URL'))
- for key, value in pycompat.items(values):
- setattr(self, key, value)
+ for key, value in values.items():
+ self[key] = value
# website
date_published = fields.Datetime('Publish Date')
@@ -385,7 +385,7 @@ class Slide(models.Model):
values['date_published'] = datetime.datetime.now()
if values.get('url') and not values.get('document_id'):
doc_data = self._parse_document_url(values['url']).get('values', dict())
- for key, value in pycompat.items(doc_data):
+ for key, value in doc_data.items():
values.setdefault(key, value)
# Do not publish slide if user has not publisher rights
if not self.user_has_groups('website.group_website_publisher'):
@@ -399,7 +399,7 @@ class Slide(models.Model):
def write(self, values):
if values.get('url') and values['url'] != self.url:
doc_data = self._parse_document_url(values['url']).get('values', dict())
- for key, value in pycompat.items(doc_data):
+ for key, value in doc_data.items():
values.setdefault(key, value)
if values.get('channel_id'):
custom_channels = self.env['slide.channel'].search([('custom_slide_id', '=', self.id), ('id', '!=', values.get('channel_id'))])
diff --git a/doc/python3.rst b/doc/python3.rst
index 7ca86708ced..c8e8269936e 100644
--- a/doc/python3.rst
+++ b/doc/python3.rst
@@ -233,10 +233,7 @@ methods or functions having been *removed entirely*:
.. important::
When possible, use comprehensions (list, generator, ...) rather than
- ``map`` or ``filter``, otherwise use the cross-version ``pycompat``
- versions (``pycompat.imap``, ``pycompat.ifilter`` and
- ``pycompat.izip``). The ``pycompat`` versions all return *iterators* and
- may need to be wrapped in a ``list()`` call to yield a list.
+ ``map`` or ``filter``.
* In Python 3, ``dict.keys``, ``dict.values`` and ``dict.items`` return
*views* rather than lists, and the ``iter*`` and ``view*`` methods have
@@ -244,11 +241,9 @@ methods or functions having been *removed entirely*:
.. important::
- Prefer using :func:`odoo.tools.pycompat.keys`,
- :func:`odoo.tools.pycompat.values` and :func:`odoo.tools.pycompat.items`
- return cross-version iterators. When needing actual lists (e.g. to
- modify a dictionary during iteration), wrap one of the calls above in a
- ``list()``.
+ When the result of the above methods is used for more than a one-shot
+ loop (e.g. to be included in returned value), or when the dict needs
+ to be modified during iteration, wrap the calls in a ``list()``.
builtins
--------
diff --git a/odoo/addons/base/ir/ir_attachment.py b/odoo/addons/base/ir/ir_attachment.py
index bd27a675eb0..41b85913ed9 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, pycompat
+from odoo.tools import config, human_size, ustr, html_escape
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 pycompat.items(checklist):
+ for fname, filepath in checklist.items():
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 pycompat.items(model_ids):
+ for res_model, res_ids in model_ids.items():
# 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 pycompat.items(model_attachments):
+ for res_model, targets in model_attachments.items():
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(*pycompat.values(targets)))
+ ids.difference_update(itertools.chain(*targets.values()))
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 833185d8d67..a286a8836ce 100644
--- a/odoo/addons/base/ir/ir_config_parameter.py
+++ b/odoo/addons/base/ir/ir_config_parameter.py
@@ -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 pycompat.items(_default_parameters):
+ for key, func in _default_parameters.items():
# 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 b8994d9221d..d7521ed6ba1 100644
--- a/odoo/addons/base/ir/ir_fields.py
+++ b/odoo/addons/base/ir/ir_fields.py
@@ -12,9 +12,9 @@ from odoo.tools import ustr, pycompat
REFERENCING_FIELDS = {None, 'id', '.id'}
def only_ref_fields(record):
- return {k: v for k, v in pycompat.items(record) if k in REFERENCING_FIELDS}
+ return {k: v for k, v in record.items() if k in REFERENCING_FIELDS}
def exclude_ref_fields(record):
- return {k: v for k, v in pycompat.items(record) if k not in REFERENCING_FIELDS}
+ return {k: v for k, v in record.items() if k not in REFERENCING_FIELDS}
CREATE = lambda values: (0, False, values)
UPDATE = lambda id, values: (1, id, values)
@@ -43,7 +43,7 @@ class IrFieldsConverter(models.AbstractModel):
if isinstance(error_params, pycompat.string_types):
error_params = sanitize(error_params)
elif isinstance(error_params, dict):
- error_params = {k: sanitize(v) for k, v in pycompat.items(error_params)}
+ error_params = {k: sanitize(v) for k, v in error_params.items()}
elif isinstance(error_params, tuple):
error_params = tuple(sanitize(v) for v in error_params)
return error_type(error_msg % error_params, error_args)
@@ -64,12 +64,12 @@ class IrFieldsConverter(models.AbstractModel):
converters = {
name: self.to_field(model, field, fromtype)
- for name, field in pycompat.items(model._fields)
+ for name, field in model._fields.items()
}
def fn(record, log):
converted = {}
- for field, value in pycompat.items(record):
+ for field, value in record.items():
if field in REFERENCING_FIELDS:
continue
if not value:
diff --git a/odoo/addons/base/ir/ir_http.py b/odoo/addons/base/ir/ir_http.py
index 392cf27d4a1..af9fde0b012 100644
--- a/odoo/addons/base/ir/ir_http.py
+++ b/odoo/addons/base/ir/ir_http.py
@@ -203,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 list(pycompat.items(arguments)):
+ for name, arg in list(arguments.items()):
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 eab160b4a84..0ecb895e082 100644
--- a/odoo/addons/base/ir/ir_mail_server.py
+++ b/odoo/addons/base/ir/ir_mail_server.py
@@ -318,7 +318,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 pycompat.items(headers):
+ for key, value in headers.items():
msg[pycompat.to_native(ustr(key))] = encode_header(value)
if subtype == 'html' and not body_alternative:
diff --git a/odoo/addons/base/ir/ir_model.py b/odoo/addons/base/ir/ir_model.py
index 2092f4cd0b2..25967c6b212 100644
--- a/odoo/addons/base/ir/ir_model.py
+++ b/odoo/addons/base/ir/ir_model.py
@@ -194,7 +194,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 pycompat.items(self._context) if k != '__last_update'})
+ self = self.with_context({k: v for k, v in self._context.items() 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):
@@ -766,7 +766,7 @@ class IrModelFields(models.Model):
fields_data[field.name] = dict(params, id=record.id)
return record
- diff = {key for key, val in pycompat.items(params) if field_data[key] != val}
+ diff = {key for key, val in params.items() if field_data[key] != val}
if diff:
cr = self.env.cr
# update the entry in this table
@@ -784,7 +784,7 @@ class IrModelFields(models.Model):
def _reflect_model(self, model):
""" Reflect the given model's fields. """
self.clear_caches()
- for field in pycompat.values(model._fields):
+ for field in model._fields.values():
self._reflect_field(field)
if not self.pool._init:
@@ -867,7 +867,7 @@ class IrModelFields(models.Model):
def _add_manual_fields(self, model):
""" Add extra fields on model. """
fields_data = self._get_manual_field_data(model._name)
- for name, field_data in pycompat.items(fields_data):
+ for name, field_data in fields_data.items():
if name not in model._fields and field_data['state'] == 'manual':
field = self._instanciate(field_data)
if field:
@@ -1278,7 +1278,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 pycompat.items(model_id_name):
+ for model, id_name in model_id_name.items():
try:
ng = self.env[model].browse(id_name).name_get()
id_name.update(ng)
@@ -1375,7 +1375,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 pycompat.items(self.env[model]._inherits):
+ for parent_model, parent_field in self.env[model]._inherits.items():
parent = record[parent_field]
parent_xid = '%s_%s' % (xml_id, parent_model.replace('.', '_'))
self.loads[(module, parent_xid)] = (parent_model, parent.id)
@@ -1430,7 +1430,7 @@ class IrModelData(models.Model):
elif record:
record.write(values)
if xml_id:
- for parent_model, parent_field in pycompat.items(record._inherits):
+ for parent_model, parent_field in record._inherits.items():
self.sudo().create({
'name': xml_id + '_' + parent_model.replace('.', '_'),
'model': parent_model,
@@ -1449,7 +1449,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 pycompat.items(record._inherits):
+ for parent_model, parent_field in record._inherits.items():
xid = self.sudo().search([
('module', '=', module),
('name', '=', xml_id + '_' + parent_model.replace('.', '_')),
@@ -1469,7 +1469,7 @@ class IrModelData(models.Model):
inherit_models = [record]
while inherit_models:
current_model = inherit_models.pop()
- for parent_model_name, parent_field in pycompat.items(current_model._inherits):
+ for parent_model_name, parent_field in current_model._inherits.items():
inherit_models.append(self.env[parent_model_name])
if parent_model_name in existing_parents:
continue
@@ -1495,7 +1495,7 @@ class IrModelData(models.Model):
if xml_id and record:
self.loads[(module, xml_id)] = (model, record.id)
- for parent_model, parent_field in pycompat.items(record._inherits):
+ for parent_model, parent_field in record._inherits.items():
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 8f894107b81..fbf0d42f8b5 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 import fields, tools
from odoo.http import request
from odoo.modules.module import get_resource_path
import psycopg2
-from odoo.tools import func, misc, pycompat
+from odoo.tools import func, misc
import logging
_logger = logging.getLogger(__name__)
@@ -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 pycompat.values(assets)):
+ if any(asset._content is None for asset in assets.values()):
outdated = True
if outdated:
diff --git a/odoo/addons/base/ir/ir_qweb/fields.py b/odoo/addons/base/ir/ir_qweb/fields.py
index 6cc5337f8a6..27d13d3076c 100644
--- a/odoo/addons/base/ir/ir_qweb/fields.py
+++ b/odoo/addons/base/ir/ir_qweb/fields.py
@@ -427,7 +427,7 @@ class BarcodeConverter(models.AbstractModel):
barcode = self.env['ir.actions.report'].barcode(
barcode_type,
value,
- **{key: value for key, value in pycompat.items(options) if key in ['width', 'height', 'humanreadable']})
+ **{key: value for key, value in options.items() if key in ['width', 'height', 'humanreadable']})
return u'
' % base64.b64encode(barcode).decode('ascii')
@api.model
diff --git a/odoo/addons/base/ir/ir_qweb/ir_qweb.py b/odoo/addons/base/ir/ir_qweb/ir_qweb.py
index 6a23054519e..bd40a2ce76c 100644
--- a/odoo/addons/base/ir/ir_qweb/ir_qweb.py
+++ b/odoo/addons/base/ir/ir_qweb/ir_qweb.py
@@ -169,7 +169,7 @@ class IrQWeb(models.AbstractModel, QWeb):
if field_options and 'monetary' in field_options:
try:
options = "{'widget': 'monetary'"
- for k, v in pycompat.items(json.loads(field_options)):
+ for k, v in json.loads(field_options).items():
if k in ('display_currency', 'from_currency'):
options = "%s, '%s': %s" % (options, k, v)
else:
diff --git a/odoo/addons/base/ir/ir_qweb/qweb.py b/odoo/addons/base/ir/ir_qweb/qweb.py
index 61bd39eab8e..43c10fe19f0 100644
--- a/odoo/addons/base/ir/ir_qweb/qweb.py
+++ b/odoo/addons/base/ir/ir_qweb/qweb.py
@@ -187,7 +187,7 @@ def foreach_iterator(base_ctx, enum, name):
if isinstance(enum, Sized):
ctx["%s_size" % name] = size = len(enum)
if isinstance(enum, Mapping):
- enum = pycompat.items(enum)
+ enum = enum.items()
else:
enum = pycompat.izip(*tee(enum))
value_key = '%s_value' % name
@@ -240,7 +240,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 pycompat.items(self)))
+ return hash(frozenset((key, freehash(val)) for key, val in self.items()))
####################################
@@ -527,7 +527,6 @@ class QWeb(object):
"""
return ast.parse(dedent("""
from collections import OrderedDict
- from odoo.tools import pycompat
from odoo.tools.pycompat import to_text, string_types
from odoo.addons.base.ir.ir_qweb.qweb import escape, foreach_iterator
"""))
@@ -745,7 +744,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(pycompat.items(el.nsmap)) - set(pycompat.items(options['nsmap'])):
+ for ns_prefix, ns_definition in set(el.nsmap.items()) - set(options['nsmap'].items()):
if ns_prefix is None:
attrib['xmlns'] = ns_definition
else:
@@ -754,9 +753,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.
- ns = itertools.chain(pycompat.items(options['nsmap']), pycompat.items(el.nsmap))
+ ns = itertools.chain(options['nsmap'].items(), el.nsmap.items())
nsprefixmap = {v: k for k, v in ns}
- for key, value in pycompat.items(el.attrib):
+ for key, value in el.attrib.items():
attrib_qname = etree.QName(key)
if attrib_qname.namespace:
attrib['%s:%s' % (nsprefixmap[attrib_qname.namespace], attrib_qname.localname)] = value
@@ -774,7 +773,7 @@ class QWeb(object):
if unqualified_el_tag == 't':
return content
- tag = u'<%s%s' % (el_tag, u''.join([u' %s="%s"' % (name, escape(pycompat.to_text(value))) for name, value in pycompat.items(attrib)]))
+ tag = u'<%s%s' % (el_tag, u''.join([u' %s="%s"' % (name, escape(pycompat.to_text(value))) for name, value in attrib.items()]))
if unqualified_el_tag in self._void_elements:
return [self._append(ast.Str(tag + '/>'))] + content
else:
@@ -786,10 +785,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 itertools.chain(pycompat.items(options['nsmap']), pycompat.items(el.nsmap))}
+ nsprefixmap = {v: k for k, v in itertools.chain(options['nsmap'].items(), el.nsmap.items())}
nodes = []
- for key, value in pycompat.items(el.attrib):
+ for key, value in el.attrib.items():
if not key.startswith('t-'):
attrib_qname = etree.QName(key)
if attrib_qname.namespace:
@@ -804,7 +803,7 @@ class QWeb(object):
We do not support namespaced dynamic attributes.
"""
nodes = []
- for name, value in pycompat.items(el.attrib):
+ for name, value in el.attrib.items():
if name.startswith('t-attf-'):
nodes.append((name[7:], self._compile_format(value)))
elif name.startswith('t-att-'):
@@ -830,7 +829,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 pycompat.items(el.attrib)):
+ if any(name.startswith('t-att') or not name.startswith('t-') for name, value in el.attrib.items()):
if not attr_already_created:
attr_already_created = True
body.append(
@@ -871,7 +870,7 @@ class QWeb(object):
)))
if attr_already_created:
- # for name, value in pycompat.items(t_attrs):
+ # for name, value in t_attrs.items():
# if value or isinstance(value, basestring)):
# append(u' ')
# append(name)
@@ -882,11 +881,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='pycompat', ctx=ast.Load()),
+ value=ast.Name(id='t_attrs', ctx=ast.Load()),
attr='items',
ctx=ast.Load()
),
- args=[ast.Name(id='t_attrs', ctx=ast.Load())], keywords=[],
+ args=[], keywords=[],
starargs=None, kwargs=None
),
body=[ast.If(
@@ -943,7 +942,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(pycompat.items(el.nsmap)) - set(pycompat.items(options['nsmap'])):
+ for ns_prefix, ns_definition in set(el.nsmap.items()) - set(options['nsmap'].items()):
if ns_prefix is None:
extra_attrib['xmlns'] = ns_definition
else:
@@ -952,7 +951,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(pycompat.to_text(value))) for name, value in pycompat.items(extra_attrib)]))))]
+ body = [self._append(ast.Str(u'<%s%s' % (el_tag, u''.join([u' %s="%s"' % (name, escape(pycompat.to_text(value))) for name, value in extra_attrib.items()]))))]
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'/>')))
@@ -1457,7 +1456,7 @@ class QWeb(object):
# make the nsmap an ast dict
keys = []
values = []
- for key, value in pycompat.items(options['nsmap']):
+ for key, value in options['nsmap'].items():
if isinstance(key, pycompat.string_types):
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 aa893e3f316..105f0f9bbf4 100644
--- a/odoo/addons/base/ir/ir_sequence.py
+++ b/odoo/addons/base/ir/ir_sequence.py
@@ -6,7 +6,6 @@ import pytz
from odoo import api, fields, models, _
from odoo.exceptions import UserError
-from odoo.tools import pycompat
_logger = logging.getLogger(__name__)
@@ -195,7 +194,7 @@ class IrSequence(models.Model):
'weekday': '%w', 'h24': '%H', 'h12': '%I', 'min': '%M', 'sec': '%S'
}
res = {}
- for key, format in pycompat.items(sequences):
+ for key, format in sequences.items():
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 02c085818d2..f77d84e758b 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 pycompat.items(env[model]._fields):
+ for field_name, field in env[model]._fields.items():
if hasattr(field, 'translate') and callable(field.translate):
src_relevant_fields.append("%s,%s" % (model, field_name))
@@ -531,7 +531,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 pycompat.items(model_ids):
+ for mname, ids in model_ids.items():
records = self.env[mname].browse(ids)
records.check_access_rights(fmode)
records.check_field_access_rights(fmode, model_fields[mname])
@@ -646,7 +646,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 pycompat.items(record._fields):
+ for name, fld in record._fields.items():
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 e848d88b093..085200a7475 100644
--- a/odoo/addons/base/ir/ir_ui_view.py
+++ b/odoo/addons/base/ir/ir_ui_view.py
@@ -845,7 +845,7 @@ actual arch.
collect(arch, self.env[model_name])
- for field, nodes in pycompat.items(field_nodes):
+ for field, nodes in field_nodes.items():
# if field should trigger an onchange, add on_change="1" on the
# nodes referring to field
model = self.env[field.model_name]
@@ -1102,12 +1102,12 @@ actual arch.
Model = self.env[model]
Node = self.env[node_obj]
- for model_key, model_value in pycompat.items(Model._fields):
+ for model_key, model_value in Model._fields.items():
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 pycompat.items(Node._fields):
+ for node_key, node_value in Node._fields.items():
if node_value.type == 'one2many':
if node_value.comodel_name == conn_obj:
# _Source_Field = "Incoming Arrows" (connected via des_node)
@@ -1184,7 +1184,7 @@ actual arch.
xmlid_filter = "AND md.name IN %s"
names = tuple(
name
- for (xmod, name), (model, res_id) in pycompat.items(self.pool.model_data_reference_ids)
+ for (xmod, name), (model, res_id) in self.pool.model_data_reference_ids.items()
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 f05241a8c05..851c4705738 100644
--- a/odoo/addons/base/ir/ir_values.py
+++ b/odoo/addons/base/ir/ir_values.py
@@ -315,7 +315,7 @@ class IrValues(models.Model):
for row in self._cr.dictfetchall():
value = pickle.loads(row['value'])
defaults.setdefault(row['name'], (row['id'], row['name'], value))
- return list(pycompat.values(defaults))
+ return list(defaults.values())
# use ormcache: this is called a lot by BaseModel.default_get()!
@api.model
@@ -428,4 +428,4 @@ class IrValues(models.Model):
results[name] = (id, name, action_def)
except (AccessError, MissingError):
continue
- return sorted(pycompat.values(results))
+ return sorted(results.values())
diff --git a/odoo/addons/base/module/module.py b/odoo/addons/base/module/module.py
index ccd4be8aa8b..cc77b392a18 100644
--- a/odoo/addons/base/module/module.py
+++ b/odoo/addons/base/module/module.py
@@ -694,7 +694,7 @@ class Module(models.Model):
_logger.debug('Install from url: %r', urls)
try:
# 1. Download & unzip missing modules
- for module_name, url in pycompat.items(urls):
+ for module_name, url in urls.items():
if not url:
continue # nothing to download, local version is already the last one
@@ -715,7 +715,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 pycompat.items(urls):
+ for module_name, url in urls.items():
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)
@@ -747,7 +747,7 @@ class Module(models.Model):
self.update_list()
- with_urls = [module_name for module_name, url in pycompat.items(urls) if url]
+ with_urls = [module_name for module_name, url in urls.items() if url]
downloaded = self.search([('name', 'in', with_urls)])
installed = self.search([('id', 'in', downloaded.ids), ('state', '=', 'installed')])
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 a933cdd9430..03632644159 100644
--- a/odoo/addons/base/module/report/ir_module_reference_print.py
+++ b/odoo/addons/base/module/report/ir_module_reference_print.py
@@ -2,7 +2,6 @@
# 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):
@@ -23,7 +22,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(pycompat.items(self.env[model].fields_get(fnames)))
+ return sorted(self.env[model].fields_get(fnames).items())
return []
@api.model
diff --git a/odoo/addons/base/res/ir_property.py b/odoo/addons/base/res/ir_property.py
index ec086fb6c61..73f8aafccad 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 pycompat.items(refs):
+ for ref, id in refs.items():
value = clean(values[id])
if value != default_value:
self.create({
diff --git a/odoo/addons/base/res/res_company.py b/odoo/addons/base/res/res_company.py
index e81af42efcb..5a711c6b9c0 100644
--- a/odoo/addons/base/res/res_company.py
+++ b/odoo/addons/base/res/res_company.py
@@ -6,7 +6,6 @@ import re
from odoo import api, fields, models, tools, _
from odoo.exceptions import ValidationError
-from odoo.tools import pycompat
class Company(models.Model):
@@ -154,7 +153,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 pycompat.items(values):
+ for fname, value in values.items():
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 ec81d2ce882..4176d57ae52 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, pycompat
+from odoo.tools import ustr
_logger = logging.getLogger(__name__)
@@ -247,7 +247,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 pycompat.items(self._fields)
+ selectable = [name for name, field in self._fields.items()
if field.type == 'boolean']
return self.env['ir.module.module'].search([('name', 'in', selectable),
('state', 'in', ['to install', 'installed', 'to upgrade'])])
@@ -272,7 +272,7 @@ class ResConfigInstaller(models.TransientModel, ResConfigModuleInstallationMixin
"""
base = set(module_name
for installer in self.read()
- for module_name, to_install in pycompat.items(installer)
+ for module_name, to_install in installer.items()
if self._fields[module_name].type == 'boolean' and to_install)
hooks_results = set()
@@ -282,7 +282,7 @@ class ResConfigInstaller(models.TransientModel, ResConfigModuleInstallationMixin
hooks_results.update(hook() or set())
additionals = set(module
- for requirements, consequences in pycompat.items(self._install_if)
+ for requirements, consequences in self._install_if.items()
if base.issuperset(requirements)
for module in consequences)
@@ -442,7 +442,7 @@ class ResConfigSettings(models.TransientModel, ResConfigModuleInstallationMixin)
ref = self.env.ref
defaults, groups, modules, others = [], [], [], []
- for name, field in pycompat.items(self._fields):
+ for name, field in self._fields.items():
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 \
diff --git a/odoo/addons/base/res/res_lang.py b/odoo/addons/base/res/res_lang.py
index f4e2d7a1578..1cdc8a5db43 100644
--- a/odoo/addons/base/res/res_lang.py
+++ b/odoo/addons/base/res/res_lang.py
@@ -8,7 +8,6 @@ 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
@@ -126,7 +125,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 pycompat.items(tools.DATETIME_FORMATS_MAP):
+ for pattern, replacement in tools.DATETIME_FORMATS_MAP.items():
format = format.replace(pattern, replacement)
return str(format)
diff --git a/odoo/addons/base/res/res_users.py b/odoo/addons/base/res/res_users.py
index 24027c6ec00..fa17d182fd5 100644
--- a/odoo/addons/base/res/res_users.py
+++ b/odoo/addons/base/res/res_users.py
@@ -761,7 +761,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(pycompat.values(order))) == len(gs):
+ if len(set(order.values())) == len(gs):
return (app, 'selection', gs.sorted(key=order.get))
else:
return (app, 'boolean', gs)
@@ -775,7 +775,7 @@ class GroupsView(models.Model):
others += g
# build the result
res = []
- for app, gs in sorted(pycompat.items(by_app), key=lambda it: it[0].sequence or 0):
+ for app, gs in sorted(by_app.items(), key=lambda it: it[0].sequence or 0):
res.append(linearize(app, gs))
if others:
res.append((self.env['ir.module.category'], 'boolean', others))
@@ -815,7 +815,7 @@ class UsersView(models.Model):
add, rem = [], []
values1 = {}
- for key, val in pycompat.items(values):
+ for key, val in values.items():
if is_boolean_group(key):
(add if val else rem).append(get_boolean_group(key))
elif is_selection_groups(key):
diff --git a/odoo/addons/base/tests/test_api.py b/odoo/addons/base/tests/test_api.py
index ad2dd1f0e85..96fba1179b7 100644
--- a/odoo/addons/base/tests/test_api.py
+++ b/odoo/addons/base/tests/test_api.py
@@ -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 pycompat.items(partners._fields):
+ for name, field in partners._fields.items():
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 pycompat.values(country_id_cache) for cid in cids)
+ country_ids = set(cid for cids in country_id_cache.values() 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 07a087d0842..f27c376c9b5 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, pycompat
+from odoo.tools import mute_logger
from odoo.osv import expression
@@ -85,10 +85,10 @@ class TestExpression(TransactionCase):
'b ab': [cids['B'], cids['AB']],
}
pids = {}
- for name, cat_ids in pycompat.items(partners_config):
+ for name, cat_ids in partners_config.items():
pids[name] = partners.create({'name': name, 'category_id': [(6, 0, cat_ids)]}).id
- base_domain = [('id', 'in', list(pycompat.values(pids)))]
+ base_domain = [('id', 'in', list(pids.values()))]
def test(op, value, expected):
found_ids = partners.search(base_domain + [('category_id', op, value)]).ids
diff --git a/odoo/addons/base/tests/test_orm.py b/odoo/addons/base/tests/test_orm.py
index bf95bee08f7..c24758dc9bf 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 pycompat.items(partners_data):
+ for name, date in partners_data.items():
p = partners.create(dict(name=name, date=date))
partner_ids.append(p.id)
partner_ids_by_day[date].append(p.id)
diff --git a/odoo/addons/base/tests/test_qweb.py b/odoo/addons/base/tests/test_qweb.py
index cfe65a00f11..ea4ef849b75 100644
--- a/odoo/addons/base/tests/test_qweb.py
+++ b/odoo/addons/base/tests/test_qweb.py
@@ -11,7 +11,7 @@ from lxml import etree
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, misc, ustr
+from odoo.tools import misc, ustr
class TestQWebTField(TransactionCase):
@@ -406,7 +406,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.assertEqual(set(pycompat.items(result_etree.nsmap)), expected_ns)
+ self.assertEqual(set(result_etree.nsmap.items()), expected_ns)
# 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 97670fdd805..1c2e60291d6 100644
--- a/odoo/addons/base/tests/test_search.py
+++ b/odoo/addons/base/tests/test_search.py
@@ -2,7 +2,6 @@
# 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):
@@ -108,7 +107,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', list(pycompat.values(cron_ids)))], order='user_id').ids
+ ids = Cron.search([('id', 'in', list(cron_ids.values()))], order='user_id').ids
expected_ids = [cron_ids[l] for l in 'ABC']
self.assertEqual(ids, expected_ids)
@@ -128,7 +127,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', list(pycompat.values(cat_ids)))]).ids
+ found_ids = Cats.search([('id', 'in', list(cat_ids.values()))]).ids
self.assertEqual(found_ids, expected_ids)
def test_13_m2o_order_loop_multi(self):
diff --git a/odoo/addons/test_pylint/tests/test_pylint.py b/odoo/addons/test_pylint/tests/test_pylint.py
index 92764eaeb84..feba409bf42 100644
--- a/odoo/addons/test_pylint/tests/test_pylint.py
+++ b/odoo/addons/test_pylint/tests/test_pylint.py
@@ -8,7 +8,6 @@ except ImportError:
pylint = None
import subprocess
from distutils.version import LooseVersion
-from os import devnull
from os.path import join
from odoo.tests.common import TransactionCase
diff --git a/odoo/api.py b/odoo/api.py
index dc51870f20a..59bd0636b11 100644
--- a/odoo/api.py
+++ b/odoo/api.py
@@ -55,7 +55,7 @@ from weakref import WeakSet
from decorator import decorator
from werkzeug.local import Local, release_local
-from odoo.tools import frozendict, classproperty, pycompat
+from odoo.tools import frozendict, classproperty
_logger = logging.getLogger(__name__)
@@ -85,7 +85,7 @@ class Params(object):
params = []
for arg in self.args:
params.append(repr(arg))
- for item in sorted(pycompat.items(self.kwargs)):
+ for item in sorted(self.kwargs.items()):
params.append("%s=%r" % item)
return ', '.join(params)
@@ -100,7 +100,7 @@ class Meta(type):
# dummy parent class to catch overridden methods decorated with 'returns'
parent = type.__new__(meta, name, bases, {})
- for key, value in list(pycompat.items(attrs)):
+ for key, value in list(attrs.items()):
if not key.startswith('__') and callable(value):
# make the method inherit from decorators
value = propagate(getattr(parent, key, None), value)
@@ -938,13 +938,13 @@ class Environment(Mapping):
# make a full copy of the cache, and invalidate it
cache_dump = dict(
(field, dict(field_cache))
- for field, field_cache in pycompat.items(self.cache)
+ for field, field_cache in self.cache.items()
)
self.invalidate_all()
# re-fetch the records, and compare with their former cache
invalids = []
- for field, field_dump in pycompat.items(cache_dump):
+ for field, field_dump in cache_dump.items():
records = self[field.model_name].browse(f for f in field_dump if f)
for record in records:
try:
diff --git a/odoo/fields.py b/odoo/fields.py
index 3779041b8e1..43ee8edbad1 100644
--- a/odoo/fields.py
+++ b/odoo/fields.py
@@ -340,7 +340,7 @@ class Field(MetaField('DummyField', (object,), {})):
def __init__(self, string=Default, **kwargs):
kwargs['string'] = string
self._sequence = kwargs['_sequence'] = next(_global_seq)
- args = {key: val for key, val in pycompat.items(kwargs) if val is not Default}
+ args = {key: val for key, val in kwargs.items() if val is not Default}
self.args = args or EMPTY_DICT
self._setup_done = None
@@ -369,7 +369,7 @@ class Field(MetaField('DummyField', (object,), {})):
""" Set all field attributes at once (with slot defaults). """
# optimization: we assign slots only
assign = object.__setattr__
- for key, val in pycompat.items(self._slots):
+ for key, val in self._slots.items():
assign(self, key, attrs.pop(key, val))
if attrs:
assign(self, '_attrs', attrs)
@@ -547,7 +547,7 @@ class Field(MetaField('DummyField', (object,), {})):
if not getattr(self, attr):
setattr(self, attr, getattr(field, prop))
- for attr, value in pycompat.items(field._attrs):
+ for attr, value in field._attrs.items():
if attr not in self._attrs:
setattr(self, attr, value)
@@ -655,7 +655,7 @@ class Field(MetaField('DummyField', (object,), {})):
model = model0.env.get(field.comodel_name)
# add self's model dependencies
- for mname, fnames in pycompat.items(model0._depends):
+ for mname, fnames in model0._depends.items():
model = model0.env[mname]
for fname in fnames:
field = model._fields[fname]
@@ -1731,7 +1731,7 @@ class Selection(Field):
if 'selection_add' in field.args:
# use an OrderedDict to update existing values
selection_add = field.args['selection_add']
- self.selection = list(pycompat.items(OrderedDict(self.selection + selection_add)))
+ self.selection = list(OrderedDict(self.selection + selection_add).items())
def _description_selection(self, env):
""" return the selection list (pairs (value, label)); labels are
@@ -1893,7 +1893,7 @@ class Many2one(_Relational):
super(Many2one, self)._setup_attrs(model, name)
# determine self.delegate
if not self.delegate:
- self.delegate = name in pycompat.values(model._inherits)
+ self.delegate = name in model._inherits.values()
def update_db(self, model, columns):
comodel = model.env[self.comodel_name]
diff --git a/odoo/http.py b/odoo/http.py
index cc94ac197ba..0f4d1ad3d97 100644
--- a/odoo/http.py
+++ b/odoo/http.py
@@ -290,7 +290,7 @@ class WebRequest(object):
def set_handler(self, endpoint, arguments, auth):
# is this needed ?
- arguments ={k: v for k, v in pycompat.items(arguments)
+ arguments ={k: v for k, v in arguments.items()
if not k.startswith("_ignored_")}
self.endpoint_arguments = arguments
self.endpoint = endpoint
@@ -839,7 +839,7 @@ more details.
"""
response = Response(data, headers=headers)
if cookies:
- for k, v in pycompat.items(cookies):
+ for k, v in cookies.items():
response.set_cookie(k, v)
return response
@@ -880,7 +880,7 @@ class ControllerType(type):
super(ControllerType, cls).__init__(name, bases, attrs)
# flag old-style methods with req as first argument
- for k, v in pycompat.items(attrs):
+ for k, v in attrs.items():
if inspect.isfunction(v) and hasattr(v, 'original_func'):
# Set routing type on original functions
routing_type = v.routing.get('type')
@@ -1136,7 +1136,7 @@ class OpenERPSession(werkzeug.contrib.sessions.Session):
# NOTE we do not store files in the session itself to avoid loading them in memory.
# By storing them in the session store, we ensure every worker (even ones on other
# servers) can access them. It also allow stale files to be deleted by `session_gc`.
- for f in pycompat.values(req.files):
+ for f in req.files.values():
storename = 'werkzeug_%s_%s.file' % (self.sid, uuid.uuid4().hex)
path = os.path.join(root.session_store.path, storename)
with open(path, 'w') as fp:
@@ -1154,7 +1154,7 @@ class OpenERPSession(werkzeug.contrib.sessions.Session):
try:
if data:
# regenerate files filenames with the current session store
- for name, (storename, filename, content_type) in pycompat.items(data['files']):
+ for name, (storename, filename, content_type) in data['files'].items():
path = os.path.join(root.session_store.path, storename)
files.add(name, (path, filename, content_type))
yield werkzeug.datastructures.CombinedMultiDict([data['form'], files])
@@ -1162,7 +1162,7 @@ class OpenERPSession(werkzeug.contrib.sessions.Session):
yield None
finally:
# cleanup files
- for f, _, _ in pycompat.values(files):
+ for f, _, _ in files.values():
try:
os.unlink(f)
except IOError:
diff --git a/odoo/models.py b/odoo/models.py
index a9cd2ded435..792e9f04182 100644
--- a/odoo/models.py
+++ b/odoo/models.py
@@ -148,7 +148,7 @@ class MetaModel(api.Meta):
self.module_to_models[self._module].append(self)
# check for new-api conversion error: leave comma after field definition
- for key, val in pycompat.items(attrs):
+ for key, val in attrs.items():
if type(val) is tuple and len(val) == 1 and isinstance(val[0], Field):
_logger.error("Trailing comma after field definition: %s.%s", self, key)
if isinstance(val, Field):
@@ -514,7 +514,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
cls._inherits.update(base._inherits)
- for mname, fnames in pycompat.items(base._depends):
+ for mname, fnames in base._depends.items():
cls._depends[mname] = cls._depends.get(mname, []) + fnames
for cons in base._constraints:
@@ -524,7 +524,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
cls._sql_constraints += base._sql_constraints
cls._sequence = cls._sequence or (cls._table + '_id_seq')
- cls._constraints = list(pycompat.values(cls._constraints))
+ cls._constraints = list(cls._constraints.values())
# update _inherits_children of parent models
for parent_name in cls._inherits:
@@ -875,7 +875,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
:returns: a list of triplets of (id, xid, record)
:rtype: list((int|None, str|None, dict))
"""
- field_names = {name: field.string for name, field in pycompat.items(self._fields)}
+ field_names = {name: field.string for name, field in self._fields.items()}
if self.env.lang:
field_names.update(self.env['ir.translation'].get_field_string(self._name))
@@ -1006,7 +1006,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
defaults = self._convert_to_write(defaults)
# add default values for inherited fields
- for model, names in pycompat.items(parent_fields):
+ for model, names in parent_fields.items():
defaults.update(self.env[model].default_get(names))
return defaults
@@ -1082,7 +1082,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
:rtype: etree._Element
"""
group = E.group(col="4")
- for fname, field in pycompat.items(self._fields):
+ for fname, field in self._fields.items():
if field.automatic:
continue
elif field.type in ('one2many', 'many2many', 'text', 'html'):
@@ -1504,14 +1504,14 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
# avoid overriding inherited values when parent is set
avoid_models = {
parent_model
- for parent_model, parent_field in pycompat.items(self._inherits)
+ for parent_model, parent_field in self._inherits.items()
if parent_field in values
}
# compute missing fields
missing_defaults = {
name
- for name, field in pycompat.items(self._fields)
+ for name, field in self._fields.items()
if name not in values
if self._log_access and name not in MAGIC_COLUMNS
if not (field.inherited and field.related_field.model_name in avoid_models)
@@ -1522,7 +1522,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
# override defaults with the provided values, never allow the other way around
defaults = self.default_get(list(missing_defaults))
- for name, value in pycompat.items(defaults):
+ for name, value in defaults.items():
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)]
@@ -1607,10 +1607,10 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
if field.relational and groups._fold_name in groups._fields:
fold = {group.id: group[groups._fold_name]
for group in groups.browse([key for key in result if key])}
- for key, line in pycompat.items(result):
+ for key, line in result.items():
line['__fold'] = fold.get(key, False)
- return list(pycompat.values(result))
+ return list(result.values())
@api.model
def _read_group_prepare(self, orderby, aggregated_fields, annotated_groupbys, query):
@@ -1844,7 +1844,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
def _read_group_raw(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
self.check_access_rights('read')
query = self._where_calc(domain)
- fields = fields or [f.name for f in pycompat.values(self._fields) if f.store]
+ fields = fields or [f.name for f in self._fields.values() if f.store]
groupby = [groupby] if isinstance(groupby, pycompat.string_types) else list(OrderedSet(groupby))
groupby_list = groupby[:1] if lazy else groupby
@@ -1918,7 +1918,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
self._read_group_resolve_many2one_fields(fetched_data, annotated_groupbys)
- data = ({k: self._read_group_prepare_data(k,v, groupby_dict) for k,v in pycompat.items(r)} for r in fetched_data)
+ data = ({k: self._read_group_prepare_data(k,v, groupby_dict) for k,v in r.items()} for r in fetched_data)
result = [self._read_group_format_result(d, annotated_groupbys, groupby, domain) for d in data]
if lazy:
# Right now, read_group only fill results in lazy mode (by default).
@@ -2024,7 +2024,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
# fields which were required but have been removed (or will be added by
# another module)
cr = self._cr
- cols = [name for name, field in pycompat.items(self._fields)
+ cols = [name for name, field in self._fields.items()
if field.store and field.column_type]
cr.execute("SELECT a.attname, a.attnotnull"
" FROM pg_class c, pg_attribute a"
@@ -2124,7 +2124,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
recs = self.with_context(active_test=False).search([])
recs._recompute_todo(field)
- for field in pycompat.values(self._fields):
+ for field in self._fields.values():
if not field.store:
continue
@@ -2212,9 +2212,9 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
""" Determine inherited fields. """
# determine candidate inherited fields
fields = {}
- for parent_model, parent_field in pycompat.items(self._inherits):
+ for parent_model, parent_field in self._inherits.items():
parent = self.env[parent_model]
- for name, field in pycompat.items(parent._fields):
+ for name, field in parent._fields.items():
# inherited fields are implemented as related fields, with the
# following specific properties:
# - reading inherited fields should not bypass access rights
@@ -2227,13 +2227,13 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
)
# add inherited fields that are not redefined locally
- for name, field in pycompat.items(fields):
+ for name, field in fields.items():
if name not in self._fields:
self._add_field(name, field)
@api.model
def _inherits_check(self):
- for table, field_name in pycompat.items(self._inherits):
+ for table, field_name in self._inherits.items():
field = self._fields.get(field_name)
if not field:
_logger.info('Missing many2one field definition for _inherits reference "%s" in "%s", using default one.', field_name, self._name)
@@ -2246,7 +2246,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
field.ondelete = "cascade"
# reflect fields with delegate=True in dictionary self._inherits
- for field in pycompat.values(self._fields):
+ for field in self._fields.values():
if field.type == 'many2one' and not field.related and field.delegate:
if not field.required:
_logger.warning("Field %s with delegate=True must be required.", field)
@@ -2334,7 +2334,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
# set up fields
bad_fields = []
- for name, field in pycompat.items(cls._fields):
+ for name, field in cls._fields.items():
try:
field.setup_full(self)
except Exception:
@@ -2353,11 +2353,11 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
# map each field to the fields computed with the same method
groups = defaultdict(list)
- for field in pycompat.values(cls._fields):
+ for field in cls._fields.values():
if field.compute:
cls._field_computed[field] = group = groups[field.compute]
group.append(field)
- for fields in pycompat.values(groups):
+ for fields in groups.values():
compute_sudo = fields[0].compute_sudo
if not all(field.compute_sudo == compute_sudo for field in fields):
_logger.warning("%s: inconsistent 'compute_sudo' for computed fields: %s",
@@ -2370,7 +2370,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
if isinstance(self, Model):
# set up field triggers (on database-persisted models only)
- for field in pycompat.values(cls._fields):
+ for field in cls._fields.values():
# dependencies of custom fields may not exist; ignore that case
exceptions = (Exception,) if field.manual else ()
with tools.ignore(*exceptions):
@@ -2409,7 +2409,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
readonly = not (has_access('write') or has_access('create'))
res = {}
- for fname, field in pycompat.items(self._fields):
+ for fname, field in self._fields.items():
if allfields and fname not in allfields:
continue
if field.groups and not self.user_has_groups(field.groups):
@@ -2421,7 +2421,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
description['states'] = {}
if attributes:
description = {key: val
- for key, val in pycompat.items(description)
+ for key, val in description.items()
if key in attributes}
res[fname] = description
@@ -2532,7 +2532,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
if self._context.get('prefetch_fields', True) and field.prefetch:
fs.update(
f
- for f in pycompat.values(self._fields)
+ for f in self._fields.values()
# select fields that can be prefetched
if f.prefetch
# discard fields with groups that the user may not access
@@ -2987,7 +2987,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
# split up fields into old-style and pure new-style ones
old_vals, new_vals, unknown = {}, {}, []
- for key, val in pycompat.items(vals):
+ for key, val in vals.items():
field = self._fields.get(key)
if field:
if field.store or field.inherited:
@@ -3059,7 +3059,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
direct = [] # list of direcly updated columns
has_trans = self.env.lang and self.env.lang != 'en_US'
single_lang = len(self.env['res.lang'].get_installed()) <= 1
- for name, val in pycompat.items(vals):
+ for name, val in vals.items():
field = self._fields[name]
if field and field.deprecated:
_logger.warning('Field %s.%s is deprecated: %s', self._name, name, field.deprecated)
@@ -3121,7 +3121,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
# defaults in context must be removed when call a one2many or many2many
rel_context = {key: val
- for key, val in pycompat.items(self._context)
+ for key, val in self._context.items()
if not key.startswith('default_')}
# call the 'write' method of fields which are not columns
@@ -3134,7 +3134,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
# write inherited fields on the corresponding parent records
unknown_fields = set(updend)
- for parent_model, parent_field in pycompat.items(self._inherits):
+ for parent_model, parent_field in self._inherits.items():
parent_ids = []
for sub_ids in cr.split_for_in_conditions(self.ids):
query = "SELECT DISTINCT %s FROM %s WHERE id IN %%s" % (parent_field, self._table)
@@ -3258,7 +3258,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
# split up fields into old-style and pure new-style ones
old_vals, new_vals, unknown = {}, {}, []
- for key, val in pycompat.items(vals):
+ for key, val in vals.items():
field = self._fields.get(key)
if field:
if field.store or field.inherited:
@@ -3295,7 +3295,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
# data of parent records to create or update, by model
tocreate = {
parent_model: {'id': vals.pop(parent_field, None)}
- for parent_model, parent_field in pycompat.items(self._inherits)
+ for parent_model, parent_field in self._inherits.items()
}
# list of column assignments defined as tuples like:
@@ -3310,7 +3310,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
upd_todo = []
unknown_fields = []
protected_fields = []
- for name, val in list(pycompat.items(vals)):
+ for name, val in list(vals.items()):
field = self._fields.get(name)
if not field:
unknown_fields.append(name)
@@ -3326,7 +3326,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
_logger.warning('No such field(s) in model %s: %s.', self._name, ', '.join(unknown_fields))
# create or update parent records
- for parent_model, parent_vals in pycompat.items(tocreate):
+ for parent_model, parent_vals in tocreate.items():
parent_id = parent_vals.pop('id')
if not parent_id:
parent_id = self.env[parent_model].create(parent_vals).id
@@ -3335,13 +3335,13 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
vals[self._inherits[parent_model]] = parent_id
# set boolean fields to False by default (to make search more powerful)
- for name, field in pycompat.items(self._fields):
+ for name, field in self._fields.items():
if field.type == 'boolean' and field.store and name not in vals:
vals[name] = False
# determine SQL values
self = self.browse()
- for name, val in pycompat.items(vals):
+ for name, val in vals.items():
field = self._fields[name]
if field.store and field.column_type:
column_val = field.convert_to_column(val, self, vals)
@@ -3373,7 +3373,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
if self.env.lang and self.env.lang != 'en_US':
# add translations for self.env.lang
- for name, val in pycompat.items(vals):
+ for name, val in vals.items():
field = self._fields[name]
if field.store and field.column_type and field.translate is True:
tname = "%s,%s" % (self._name, name)
@@ -3421,7 +3421,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
# defaults in context must be removed when call a one2many or many2many
rel_context = {key: val
- for key, val in pycompat.items(self._context)
+ for key, val in self._context.items()
if not key.startswith('default_')}
# call the 'write' method of fields which are not columns
@@ -3726,11 +3726,11 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
# build a black list of fields that should not be copied
blacklist = set(MAGIC_COLUMNS + ['parent_left', 'parent_right'])
- whitelist = set(name for name, field in pycompat.items(self._fields) if not field.inherited)
+ whitelist = set(name for name, field in self._fields.items() if not field.inherited)
def blacklist_given_fields(model):
# blacklist the fields that are given by inheritance
- for parent_model, parent_field in pycompat.items(model._inherits):
+ for parent_model, parent_field in model._inherits.items():
blacklist.add(parent_field)
if parent_field in default:
# all the fields of 'parent_model' are given by the record:
@@ -3739,17 +3739,17 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
else:
blacklist_given_fields(self.env[parent_model])
# blacklist deprecated fields
- for name, field in pycompat.items(model._fields):
+ for name, field in model._fields.items():
if field.deprecated:
blacklist.add(name)
blacklist_given_fields(self)
fields_to_copy = {name: field
- for name, field in pycompat.items(self._fields)
+ for name, field in self._fields.items()
if field.copy and name not in default and name not in blacklist}
- for name, field in pycompat.items(fields_to_copy):
+ for name, field in fields_to_copy.items():
if field.type == 'one2many':
# duplicate following the order of the ids because we'll rely on
# it later for copying translations in copy_translation()!
@@ -3787,7 +3787,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
old_wo_lang, new_wo_lang = (old + new).with_context(lang=None)
Translation = old.env['ir.translation']
- for name, field in pycompat.items(old._fields):
+ for name, field in old._fields.items():
if not field.copy:
continue
@@ -3970,7 +3970,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
"""
results = self._get_external_ids()
return {key: val[0] if val else ''
- for key, val in pycompat.items(results)}
+ for key, val in results.items()}
# backwards compatibility
get_xml_id = get_external_id
@@ -4343,7 +4343,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
target = self if update else self.browse([], self._prefetch)
return {
name: fields[name].convert_to_cache(value, target, validate=validate)
- for name, value in pycompat.items(values)
+ for name, value in values.items()
if name in fields
}
@@ -4353,14 +4353,14 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
"""
return {
name: self._fields[name].convert_to_record(value, self)
- for name, value in pycompat.items(values)
+ for name, value in values.items()
}
def _convert_to_write(self, values):
""" Convert the ``values`` dictionary into the format of :meth:`write`. """
fields = self._fields
result = {}
- for name, value in pycompat.items(values):
+ for name, value in values.items():
if name in fields:
field = fields[name]
value = field.convert_to_cache(value, self, validate=False)
@@ -4447,7 +4447,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
def update(self, values):
""" Update the records in ``self`` with ``values``. """
for record in self:
- for name, value in pycompat.items(values):
+ for name, value in values.items():
record[name] = value
#
@@ -4692,7 +4692,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
if fnames is None:
if ids is None:
return self.env.invalidate_all()
- fields = list(pycompat.values(self._fields))
+ fields = list(self._fields.values())
else:
fields = [self._fields[n] for n in fnames]
@@ -4784,7 +4784,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
updates[frozendict(vals)].add(rec.id)
# update records in batch when possible
with recs.env.norecompute():
- for vals, ids in pycompat.items(updates):
+ for vals, ids in updates.items():
recs.browse(ids)._write(dict(vals))
# mark computed fields as done
for f in fs:
@@ -4818,7 +4818,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
if not result.get(names):
result[names] = node.attrib.get('on_change')
# traverse the subviews included in relational fields
- for subinfo in pycompat.values(info['fields'][name].get('views', {})):
+ for subinfo in info['fields'][name].get('views', {}).values():
process(etree.fromstring(subinfo['arch']), subinfo, names)
else:
for child in node:
@@ -4841,7 +4841,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
return
if res.get('value'):
res['value'].pop('id', None)
- self.update({key: val for key, val in pycompat.items(res['value']) if key in self._fields})
+ self.update({key: val for key, val in res['value'].items() if key in self._fields})
if res.get('domain'):
result.setdefault('domain', {}).update(res['domain'])
if res.get('warning'):
@@ -4970,7 +4970,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
record.mapped(field_seq)
# determine which fields have been modified
- for name, oldval in pycompat.items(values):
+ for name, oldval in values.items():
field = self._fields[name]
newval = record[name]
if newval != oldval or (
@@ -5046,7 +5046,7 @@ class RecordCache(MutableMapping):
"""
if args and isinstance(args[0], SpecialValue):
values = dict.fromkeys(self._recs._ids, args[0])
- for name, field in pycompat.items(self._recs._fields):
+ for name, field in self._recs._fields.items():
if name != 'id':
self._recs.env.cache[field].update(values)
else:
@@ -5064,7 +5064,7 @@ class RecordCache(MutableMapping):
""" Iterate over the field names with a regular value in cache. """
cache, id = self._recs.env.cache, self._recs.id
dummy = SpecialValue(None)
- for name, field in pycompat.items(self._recs._fields):
+ for name, field in self._recs._fields.items():
if name != 'id' and not isinstance(cache[field].get(id, dummy), SpecialValue):
yield name
diff --git a/odoo/modules/graph.py b/odoo/modules/graph.py
index 731b6f6557a..0f2e329fab9 100644
--- a/odoo/modules/graph.py
+++ b/odoo/modules/graph.py
@@ -8,7 +8,6 @@ import logging
import odoo
import odoo.tools as tools
-from odoo.tools import pycompat
_logger = logging.getLogger(__name__)
@@ -36,7 +35,7 @@ class Graph(dict):
return
# update the graph with values from the database (if exist)
## First, we set the default values for each package in graph
- additional_data = {key: {'id': 0, 'state': 'uninstalled', 'dbdemo': False, 'installed_version': None} for key in pycompat.keys(self)}
+ additional_data = {key: {'id': 0, 'state': 'uninstalled', 'dbdemo': False, 'installed_version': None} for key in self.keys()}
## Then we get the values from the database
cr.execute('SELECT name, id, state, demo AS dbdemo, latest_version AS installed_version'
' FROM ir_module_module'
@@ -46,8 +45,8 @@ class Graph(dict):
## and we update the default values with values from the database
additional_data.update((x['name'], x) for x in cr.dictfetchall())
- for package in pycompat.values(self):
- for k, v in pycompat.items(additional_data[package.name]):
+ for package in self.values():
+ for k, v in additional_data[package.name].items():
setattr(package, k, v)
def add_module(self, cr, module, force=None):
@@ -102,9 +101,9 @@ class Graph(dict):
def __iter__(self):
level = 0
- done = set(pycompat.keys(self))
+ done = set(self.keys())
while done:
- level_modules = sorted((name, module) for name, module in pycompat.items(self) if module.depth==level)
+ level_modules = sorted((name, module) for name, module in self.items() if module.depth==level)
for name, module in level_modules:
done.remove(name)
yield module
diff --git a/odoo/modules/loading.py b/odoo/modules/loading.py
index bd58376a7b9..c06c219f7eb 100644
--- a/odoo/modules/loading.py
+++ b/odoo/modules/loading.py
@@ -20,7 +20,6 @@ import odoo.tools as tools
from odoo import api, SUPERUSER_ID
from odoo.modules.module import adapt_version, initialize_sys_path, load_openerp_module
-from odoo.tools import pycompat
_logger = logging.getLogger(__name__)
_test_logger = logging.getLogger('odoo.tests')
@@ -298,13 +297,13 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
_check_module_names(cr, itertools.chain(tools.config['init'], tools.config['update']))
- module_names = [k for k, v in pycompat.items(tools.config['init']) if v]
+ module_names = [k for k, v in tools.config['init'].items() if v]
if module_names:
modules = Module.search([('state', '=', 'uninstalled'), ('name', 'in', module_names)])
if modules:
modules.button_install()
- module_names = [k for k, v in pycompat.items(tools.config['update']) if v]
+ module_names = [k for k, v in tools.config['update'].items() if v]
if module_names:
modules = Module.search([('state', '=', 'installed'), ('name', 'in', module_names)])
if modules:
@@ -392,7 +391,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
getattr(py_module, uninstall_hook)(cr, registry)
Module = env['ir.module.module']
- Module.browse(pycompat.values(modules_to_remove)).module_uninstall()
+ Module.browse(modules_to_remove.values()).module_uninstall()
# Recursive reload, should only happen once, because there should be no
# modules to remove next time
cr.commit()
@@ -415,7 +414,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
_logger.info('Modules loaded.')
# STEP 8: call _register_hook on every model
- for model in pycompat.values(env):
+ for model in env.values():
model._register_hook()
# STEP 9: save installed/updated modules for post-install tests
diff --git a/odoo/modules/migration.py b/odoo/modules/migration.py
index 0fa6699cf24..8edc9586415 100644
--- a/odoo/modules/migration.py
+++ b/odoo/modules/migration.py
@@ -13,7 +13,6 @@ from os.path import join as opj
from odoo.modules.module import get_resource_path
import odoo.release as release
import odoo.tools as tools
-from odoo.tools import pycompat
from odoo.tools.parse_version import parse_version
@@ -90,8 +89,8 @@ class MigrationManager(object):
def _get_migration_versions(pkg):
versions = sorted({
ver
- for lv in pycompat.values(self.migrations[pkg.name])
- for ver, lf in pycompat.items(lv)
+ for lv in self.migrations[pkg.name].values()
+ for ver, lf in lv.items()
if lf
}, key=lambda k: parse_version(convert_version(k)))
return versions
diff --git a/odoo/modules/registry.py b/odoo/modules/registry.py
index cade92c23ac..1efc6aa195f 100644
--- a/odoo/modules/registry.py
+++ b/odoo/modules/registry.py
@@ -17,7 +17,7 @@ import odoo
from .. import SUPERUSER_ID
from odoo.tools import (assertion_report, config, existing_tables,
lazy_classproperty, lazy_property, table_exists,
- topological_sort, OrderedSet, pycompat)
+ topological_sort, OrderedSet)
from odoo.tools.lru import LRU
_logger = logging.getLogger(__name__)
@@ -157,7 +157,7 @@ class Registry(Mapping):
def delete_all(cls):
""" Delete all the registries. """
with cls._lock:
- for db_name in list(pycompat.keys(cls.registries)):
+ for db_name in list(cls.registries.keys()):
cls.delete(db_name)
#
@@ -193,8 +193,8 @@ class Registry(Mapping):
# map fields on their dependents
dependents = {
field: set(dep for dep, _ in model._field_triggers[field] if dep != field)
- for model in pycompat.values(self)
- for field in pycompat.values(model._fields)
+ for model in self.values()
+ for field in model._fields.values()
}
# sort them topologically, and associate a sequence number to each field
mapping = {
@@ -262,7 +262,7 @@ class Registry(Mapping):
env['ir.model']._add_manual_models()
# prepare the setup on all models
- models = list(pycompat.values(env))
+ models = list(env.values())
for model in models:
model._prepare_setup()
@@ -316,7 +316,7 @@ class Registry(Mapping):
missing = {table2model[table] for table in missing_tables}
_logger.warning("Models have no table: %s.", ", ".join(missing))
# recreate missing tables following model dependencies
- deps = {name: model._depends for name, model in pycompat.items(env)}
+ deps = {name: model._depends for name, model in env.items()}
for name in topological_sort(deps):
if name in missing:
_logger.info("Recreate table of model %s.", name)
@@ -341,7 +341,7 @@ class Registry(Mapping):
""" Clear the caches associated to methods decorated with
``tools.ormcache`` or ``tools.ormcache_multi`` for all the models.
"""
- for model in pycompat.values(self.models):
+ for model in self.models.values():
model.clear_caches()
def setup_signaling(self):
diff --git a/odoo/osv/orm.py b/odoo/osv/orm.py
index f189638582b..f7cc7ae0701 100644
--- a/odoo/osv/orm.py
+++ b/odoo/osv/orm.py
@@ -46,12 +46,12 @@ def transfer_field_to_modifiers(field, modifiers):
for attr in ('invisible', 'readonly', 'required'):
state_exceptions[attr] = []
default_values[attr] = bool(field.get(attr))
- for state, modifs in pycompat.items(field.get("states",{})):
+ for state, modifs in field.get("states",{}).items():
for modif in modifs:
if default_values[modif[0]] != modif[1]:
state_exceptions[modif[0]].append(state)
- for attr, default_value in pycompat.items(default_values):
+ for attr, default_value in default_values.items():
if state_exceptions[attr]:
modifiers[attr] = [("state", "not in" if default_value else "in", state_exceptions[attr])]
else:
diff --git a/odoo/service/model.py b/odoo/service/model.py
index 185d5ce72cc..47eeeab1af1 100644
--- a/odoo/service/model.py
+++ b/odoo/service/model.py
@@ -10,7 +10,6 @@ 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 _
@@ -68,10 +67,6 @@ def check(f):
except Exception:
pass
- uid = 1
- if args and isinstance(args[0], pycompat.integer_types):
- uid = args[0]
-
lang = ctx and ctx.get('lang')
if not (lang or hasattr(src, '__call__')):
return src
@@ -119,7 +114,7 @@ def check(f):
time.sleep(wait_time)
except IntegrityError as inst:
registry = odoo.registry(dbname)
- for key in pycompat.keys(registry._sql_error):
+ for key in registry._sql_error.keys():
if key in inst[0]:
raise ValidationError(tr(registry._sql_error[key], 'sql_constraint') or inst[0])
if inst.pgcode in (errorcodes.NOT_NULL_VIOLATION, errorcodes.FOREIGN_KEY_VIOLATION, errorcodes.RESTRICT_VIOLATION):
diff --git a/odoo/service/server.py b/odoo/service/server.py
index 56acaaed901..b05b93dd825 100644
--- a/odoo/service/server.py
+++ b/odoo/service/server.py
@@ -40,7 +40,7 @@ from odoo.modules.module import run_unit_tests, runs_post_install
from odoo.modules.registry import Registry
from odoo.release import nt_service_name
from odoo.tools import config
-from odoo.tools import stripped_sys_argv, dumpstacks, log_ormcache_stats, pycompat
+from odoo.tools import stripped_sys_argv, dumpstacks, log_ormcache_stats
_logger = logging.getLogger(__name__)
@@ -216,7 +216,7 @@ class ThreadedServer(CommonServer):
time.sleep(SLEEP_INTERVAL + number) # Steve Reich timing style
registries = odoo.modules.registry.Registry.registries
_logger.debug('cron%d polling for jobs', number)
- for db_name, registry in pycompat.items(registries):
+ for db_name, registry in registries.items():
while registry.ready:
try:
acquired = ir_cron._acquire_job(db_name)
@@ -525,7 +525,7 @@ class PreforkServer(CommonServer):
def process_timeout(self):
now = time.time()
- for (pid, worker) in pycompat.items(self.workers):
+ for (pid, worker) in self.workers.items():
if worker.watchdog_timeout is not None and \
(now - worker.watchdog_time) >= worker.watchdog_timeout:
_logger.error("%s (%s) timeout after %ss",
@@ -546,8 +546,8 @@ class PreforkServer(CommonServer):
def sleep(self):
try:
# map of fd -> worker
- fds = {w.watchdog_pipe[0]: w for k, w in pycompat.items(self.workers)}
- fd_in = list(pycompat.keys(fds)) + [self.pipe[0]]
+ fds = {w.watchdog_pipe[0]: w for w in self.workers.values()}
+ fd_in = list(fds) + [self.pipe[0]]
# check for ping or internal wakeups
ready = select.select(fd_in, [], [], self.beat)
# update worker watchdogs
@@ -887,7 +887,7 @@ def load_test_file_yml(registry, test_file):
def load_test_file_py(registry, test_file):
# Locate python module based on its filename and run the tests
test_path, _ = os.path.splitext(os.path.abspath(test_file))
- for mod_name, mod_mod in list(pycompat.items(sys.modules)):
+ for mod_name, mod_mod in list(sys.modules.items()):
if mod_mod:
mod_path, _ = os.path.splitext(getattr(mod_mod, '__file__', ''))
if test_path == mod_path:
diff --git a/odoo/sql_db.py b/odoo/sql_db.py
index efc0e51972d..749abc69932 100644
--- a/odoo/sql_db.py
+++ b/odoo/sql_db.py
@@ -21,8 +21,6 @@ from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ
from psycopg2.pool import PoolError
from werkzeug import urls
-from .tools import pycompat
-
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
_logger = logging.getLogger(__name__)
@@ -43,7 +41,7 @@ def undecimalize(symb, cr):
return None
return float(symb)
-for name, typeoid in pycompat.items(types_mapping):
+for name, typeoid in types_mapping.items():
psycopg2.extensions.register_type(psycopg2.extensions.new_type(typeoid, name, lambda x, cr: x))
psycopg2.extensions.register_type(psycopg2.extensions.new_type((700, 701, 1700,), 'float', undecimalize))
@@ -269,7 +267,7 @@ class Cursor(object):
sqllogs = {'from': self.sql_from_log, 'into': self.sql_into_log}
sum = 0
if sqllogs[type]:
- sqllogitems = pycompat.items(sqllogs[type])
+ sqllogitems = sqllogs[type].items()
_logger.debug("SQL LOG %s:", type)
for r in sorted(sqllogitems, key=lambda k: k[1]):
delay = timedelta(microseconds=r[1][1])
diff --git a/odoo/tools/cache.py b/odoo/tools/cache.py
index 1226038a21c..b6b23175773 100644
--- a/odoo/tools/cache.py
+++ b/odoo/tools/cache.py
@@ -202,10 +202,10 @@ def log_ormcache_stats(sig=None, frame=None):
me = threading.currentThread()
me_dbname = getattr(me, 'dbname', 'n/a')
entries = defaultdict(int)
- for dbname, reg in pycompat.items(Registry.registries):
+ for dbname, reg in Registry.registries.items():
for key in reg.cache:
entries[(dbname,) + key[:2]] += 1
- for key, count in sorted(pycompat.items(entries)):
+ for key, count in sorted(entries.items()):
dbname, model_name, method = key
me.dbname = dbname
stat = STAT[key]
diff --git a/odoo/tools/config.py b/odoo/tools/config.py
index ee6c03a7e2e..f95e50f7dce 100644
--- a/odoo/tools/config.py
+++ b/odoo/tools/config.py
@@ -55,7 +55,7 @@ def _deduplicate_loggers(loggers):
# there are no duplicates within the output sequence
return (
'{}:{}'.format(logger, level)
- for logger, level in pycompat.items(dict(it.split(':') for it in loggers))
+ for logger, level in dict(it.split(':') for it in loggers).items()
)
@@ -527,9 +527,9 @@ class configmanager(object):
def save(self):
p = ConfigParser.RawConfigParser()
- loglevelnames = dict(pycompat.izip(pycompat.values(self._LOGLEVELS), pycompat.keys(self._LOGLEVELS)))
+ loglevelnames = dict(pycompat.izip(self._LOGLEVELS.values(), self._LOGLEVELS))
p.add_section('options')
- for opt in sorted(pycompat.keys(self.options)):
+ for opt in sorted(self.options):
if opt in ('version', 'language', 'translate_out', 'translate_in', 'overwrite_existing_translations', 'init', 'update'):
continue
if opt in self.blacklist_for_save:
@@ -541,9 +541,9 @@ class configmanager(object):
else:
p.set('options', opt, self.options[opt])
- for sec in sorted(pycompat.keys(self.misc)):
+ for sec in sorted(self.misc):
p.add_section(sec)
- for opt in sorted(pycompat.keys(self.misc[sec])):
+ for opt in sorted(self.misc[sec]):
p.set(sec,opt,self.misc[sec][opt])
# try to create the directories and write the file
diff --git a/odoo/tools/graph.py b/odoo/tools/graph.py
index 5e3edabf05a..d43088d97ab 100755
--- a/odoo/tools/graph.py
+++ b/odoo/tools/graph.py
@@ -5,8 +5,6 @@
import operator
import math
-from odoo.tools import pycompat
-
class graph(object):
def __init__(self, nodes, transitions, no_ancester=None):
@@ -259,7 +257,7 @@ class graph(object):
"""The ranks are normalized by setting the least rank to zero.
"""
- least_rank = min(x['x'] for x in pycompat.values(self.result.values))
+ least_rank = min(x['x'] for x in self.result.values.values())
if least_rank!=0:
for node in self.result:
@@ -383,7 +381,7 @@ class graph(object):
"""Finds actual-order of the nodes with respect to maximum number of nodes in a rank in component
"""
mid_pos = 0.0
- max_level = max(len(x) for x in pycompat.values(self.levels.values))
+ max_level = max(len(x) for x in self.levels.values.values())
for level in self.levels:
if level:
@@ -474,7 +472,7 @@ class graph(object):
"""
if self.Is_Cyclic:
- max_level = max(len(x) for x in pycompat.values(self.levels.values))
+ max_level = max(len(x) for x in self.levels.values.values())
if max_level%2:
self.result[self.start]['y'] = (max_level+1)/2 + self.max_order + (self.max_order and 1)
@@ -486,7 +484,7 @@ class graph(object):
else:
self.result[self.start]['y'] = 0
self.tree_order(self.start, 0)
- min_order = math.fabs(min(x['y'] for x in pycompat.values(self.result.values)))
+ min_order = math.fabs(min(x['y'] for x in self.result.values.values()))
index = self.start_nodes.index(self.start)
same = False
@@ -540,7 +538,7 @@ class graph(object):
self.result[start]['y'] = base + factor
factor += 1
- self.max_order = max(x['y'] for x in pycompat.values(self.result.values))
+ self.max_order = max(x['y'] for x in self.result.values.values())
def find_starts(self):
"""Finds other start nodes of the graph in the case when graph is disconneted
@@ -660,7 +658,7 @@ class graph(object):
for node in self.no_ancester:
for sec_node in self.transitions.get(node, []):
- if sec_node in pycompat.keys(self.partial_order):
+ if sec_node in self.partial_order:
self.transitions[self.start_nodes[0]].append(node)
break
@@ -746,7 +744,7 @@ if __name__=='__main__':
for node in nodes:
node_res[node] = result[node]
- for name,node in pycompat.items(node_res):
+ for name, node in node_res.items():
draw.arc( (int(node['y']-radius), int(node['x']-radius),int(node['y']+radius), int(node['x']+radius) ), 0, 360, (128,128,128))
draw.text( (int(node['y']), int(node['x'])), str(name), (128,128,128))
diff --git a/odoo/tools/lru.py b/odoo/tools/lru.py
index 21ecaf6383a..119fce0e1ee 100644
--- a/odoo/tools/lru.py
+++ b/odoo/tools/lru.py
@@ -2,7 +2,6 @@
# taken from http://code.activestate.com/recipes/252524-length-limited-o1-lru-cache-implementation/
import threading
-from odoo.tools import pycompat
from .func import synchronized
__all__ = ['LRU']
@@ -110,12 +109,11 @@ class LRU(object):
@synchronized()
def itervalues(self):
- for i,j in pycompat.items(self):
- yield j
+ return iter(self.d.values())
@synchronized()
def keys(self):
- return list(pycompat.keys(self.d))
+ return list(self.d)
@synchronized()
def pop(self,key):
diff --git a/odoo/tools/mail.py b/odoo/tools/mail.py
index b45de63cc71..288defdcf1f 100644
--- a/odoo/tools/mail.py
+++ b/odoo/tools/mail.py
@@ -85,7 +85,7 @@ class _Cleaner(clean.Cleaner):
new_node.text = text
new_node.tail = tail
if attrs:
- for key, val in pycompat.items(attrs):
+ for key, val in attrs.items():
new_node.set(key, val)
return new_node
@@ -154,7 +154,7 @@ class _Cleaner(clean.Cleaner):
if style[0].lower() in self._style_whitelist:
valid_styles[style[0].lower()] = style[1]
if valid_styles:
- el.attrib['style'] = '; '.join('%s: %s' % (key, val) for (key, val) in pycompat.items(valid_styles))
+ el.attrib['style'] = '; '.join('%s: %s' % (key, val) for (key, val) in valid_styles.items())
else:
del el.attrib['style']
diff --git a/odoo/tools/mimetypes.py b/odoo/tools/mimetypes.py
index 663f35be9b9..59421cf8bb6 100644
--- a/odoo/tools/mimetypes.py
+++ b/odoo/tools/mimetypes.py
@@ -10,8 +10,6 @@ import logging
import re
import zipfile
-from odoo.tools import pycompat
-
__all__ = ['guess_mimetype']
_logger = logging.getLogger(__name__)
@@ -35,7 +33,7 @@ def _check_ooxml(data):
# then there is a directory whose name denotes the type of the file:
# word, pt (powerpoint) or xl (excel)
- for dirname, mime in pycompat.items(_ooxml_dirs):
+ for dirname, mime in _ooxml_dirs.items():
if any(entry.startswith(dirname) for entry in filenames):
return mime
diff --git a/odoo/tools/misc.py b/odoo/tools/misc.py
index 274ae4a6d24..9116e08cec8 100644
--- a/odoo/tools/misc.py
+++ b/odoo/tools/misc.py
@@ -479,7 +479,7 @@ def logged(f):
vector = ['Call -> function: %r' % f]
for i, arg in enumerate(args):
vector.append(' arg %02d: %s' % (i, pformat(arg)))
- for key, value in pycompat.items(kwargs):
+ for key, value in kwargs.items():
vector.append(' kwarg %10s: %s' % (key, pformat(value)))
timeb4 = time.time()
@@ -908,7 +908,7 @@ def dumpstacks(sig=None, frame=None):
'dbname': getattr(th, 'dbname', 'n/a'),
'url': getattr(th, 'url', 'n/a')}
for th in threading.enumerate()}
- for threadId, stack in pycompat.items(sys._current_frames()):
+ for threadId, stack in sys._current_frames().items():
thread_info = threads_info.get(threadId, {})
code.append("\n# Thread: %s (id:%s) (db:%s) (uid:%s) (url:%s)" %
(thread_info.get('name', 'n/a'),
@@ -960,7 +960,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 pycompat.items(self)))
+ return hash(frozenset((key, freehash(val)) for key, val in self.items()))
class Collector(Mapping):
""" A mapping from keys to lists. This is essentially a space optimization
diff --git a/odoo/tools/pycompat.py b/odoo/tools/pycompat.py
index 89bf96c3dd6..feb65da7a67 100644
--- a/odoo/tools/pycompat.py
+++ b/odoo/tools/pycompat.py
@@ -27,10 +27,6 @@ if PY2:
integer_types = (int, long)
- keys = lambda d: iter(d.iterkeys())
- values = lambda d: iter(d.itervalues())
- items = lambda d: iter(d.iteritems())
-
# noinspection PyUnresolvedReferences
from itertools import imap, izip, ifilter
@@ -74,10 +70,6 @@ else:
integer_types = (int,)
- keys = lambda d: iter(d.keys())
- values = lambda d: iter(d.values())
- items = lambda d: iter(d.items())
-
imap = map
izip = zip
ifilter = filter
diff --git a/odoo/tools/test_reports.py b/odoo/tools/test_reports.py
index 6a6401eb896..a3588577c08 100644
--- a/odoo/tools/test_reports.py
+++ b/odoo/tools/test_reports.py
@@ -173,7 +173,7 @@ def try_report_action(cr, uid, action_id, active_model=None, active_ids=None,
view_data.update(wiz_data)
_logger.debug("View data is: %r", view_data)
- for fk, field in pycompat.items(view_res.get('fields',{})):
+ for fk, field in view_res.get('fields',{}).items():
# Default fields returns list of int, while at create()
# we need to send a [(6,0,[int,..])]
if field['type'] in ('one2many', 'many2many') \
diff --git a/odoo/tools/translate.py b/odoo/tools/translate.py
index f958772514e..a9f8c8fd57f 100644
--- a/odoo/tools/translate.py
+++ b/odoo/tools/translate.py
@@ -258,7 +258,7 @@ def translate_xml_node(node, callback, parse, serialize):
append_content(result, translate_content(todo) if todo_has_text else todo)
# translate the required attributes
- for name, value in pycompat.items(result.attrib):
+ for name, value in result.attrib.items():
if name in TRANSLATED_ATTRS:
result.set(name, translate_text(value) or value)
@@ -678,7 +678,7 @@ def trans_export(lang, modules, buffer, format, cr):
row.setdefault('tnrs', []).append((type, name, res_id))
row.setdefault('comments', set()).update(comments)
- for src, row in sorted(pycompat.items(grouped_rows)):
+ for src, row in sorted(grouped_rows.items()):
if not lang:
# translation template, so no translation value
row['translation'] = ''
@@ -692,7 +692,7 @@ def trans_export(lang, modules, buffer, format, cr):
module = row[0]
rows_by_module.setdefault(module, []).append(row)
tmpdir = tempfile.mkdtemp()
- for mod, modrows in pycompat.items(rows_by_module):
+ for mod, modrows in rows_by_module.items():
tmpmoddir = join(tmpdir, mod, 'i18n')
os.makedirs(tmpmoddir)
pofilename = (lang if lang else mod) + ".po" + ('t' if not lang else '')
@@ -1125,7 +1125,7 @@ def trans_load_data(cr, fileobj, fileformat, lang, lang_name=None, verbose=True,
# Then process the entries implied by the POT file (which is more
# correct w.r.t. the targets) if some of them remain.
pot_rows = []
- for src, target in pycompat.items(pot_targets):
+ for src, target in pot_targets.items():
if target.value:
for type, name, res_id in target.targets:
pot_rows.append((type, name, res_id, src, target.value, target.comments))
diff --git a/odoo/tools/yaml_import.py b/odoo/tools/yaml_import.py
index 6cf4cc357eb..79f997045a2 100644
--- a/odoo/tools/yaml_import.py
+++ b/odoo/tools/yaml_import.py
@@ -198,7 +198,7 @@ class YamlInterpreter(object):
def process_assert(self, node):
if isinstance(node, dict):
- assertion, expressions = next(pycompat.items(node))
+ assertion, expressions = list(node.items())[0]
else:
assertion, expressions = node, []
@@ -271,7 +271,7 @@ class YamlInterpreter(object):
return record_dict
def process_record(self, node):
- record, fields = next(pycompat.items(node))
+ record, fields = list(node.items())[0]
model = self.env[record.model]
view_id = record.view
if view_id and (view_id is not True) and isinstance(view_id, pycompat.string_types):
@@ -376,7 +376,7 @@ class YamlInterpreter(object):
def process_vals(fg, vals):
""" sanitize the given field values """
result = {}
- for field_name, field_value in pycompat.items(vals):
+ for field_name, field_value in vals.items():
if field_name not in fg:
continue
if fg[field_name]['type'] == 'many2one' and isinstance(field_value, (tuple, list)):
@@ -397,7 +397,7 @@ class YamlInterpreter(object):
def post_process(fg, elems, vals):
""" filter out readonly fields from vals """
result = {}
- for field_name, field_value in pycompat.items(vals):
+ for field_name, field_value in vals.items():
if is_readonly(elems[field_name]):
continue
if fg[field_name]['type'] in ('one2many', 'many2many'):
@@ -443,7 +443,7 @@ class YamlInterpreter(object):
record_dict.update(process_vals(fg, result.get('value', {})))
# fill in fields, and execute onchange where necessary
- for field_name, field_elem in pycompat.items(elems):
+ for field_name, field_elem in elems.items():
assert field_name in fg, "The field '%s' is defined in the form view but not on the object '%s'!" % (field_name, model._name)
if is_readonly(field_elem):
# skip readonly fields
@@ -473,7 +473,7 @@ class YamlInterpreter(object):
result = recs.onchange(dict(record_dict, **parent_values), field_name, onchange_spec)
record_dict.update(process_vals(fg, {
key: val
- for key, val in pycompat.items(result.get('value', {}))
+ for key, val in result.get('value', {}).items()
if key not in fields # do not shadow values explicitly set in yaml
}))
@@ -482,7 +482,7 @@ class YamlInterpreter(object):
else:
record_dict = {}
- for field_name, expression in pycompat.items(fields):
+ for field_name, expression in fields.items():
if record_dict.get(field_name):
continue
field_value = self._eval_field(model, field_name, expression, parent=record_dict, default=False, context=context)
@@ -493,7 +493,7 @@ class YamlInterpreter(object):
# should not be sent to create. This bug appears with not stored function fields in the new API.
return {
key: val
- for key, val in pycompat.items(record_dict)
+ for key, val in record_dict.items()
for field in [model._fields[key].base_field]
if field.store or field.inverse
}
@@ -579,7 +579,7 @@ class YamlInterpreter(object):
self.sudo_env = self.env(user=SUPERUSER_ID)
def process_python(self, node):
- python, statements = next(pycompat.items(node))
+ python, statements = list(node.items())[0]
assert python.model or python.id, "!python node must have attribute `model` or `id`"
if python.id is None:
record = self.env[python.model]
@@ -639,7 +639,7 @@ class YamlInterpreter(object):
return args
def process_function(self, node):
- function, params = next(pycompat.items(node))
+ function, params = list(node.items())[0]
if self.isnoupdate(function) and self.mode != 'init':
return
model = self.env[function.model]
@@ -769,9 +769,9 @@ class YamlInterpreter(object):
def process_ir_set(self, node):
if not self.mode == 'init':
return False
- _, fields = next(pycompat.items(node))
+ _, fields = list(node.items())[0]
res = {}
- for fieldname, expression in pycompat.items(fields):
+ for fieldname, expression in fields.items():
if is_eval(expression):
value = safe_eval(expression.expression, self.eval_context)
else:
@@ -877,7 +877,7 @@ class YamlInterpreter(object):
elif not is_preceded_by_comment:
if isinstance(node, dict):
msg = "Creating %s\n with %s"
- args = next(pycompat.items(node))
+ args = list(node.items())[0]
self._log(msg, *args)
else:
self._log(node)
diff --git a/odoo/tools/yaml_tag.py b/odoo/tools/yaml_tag.py
index 2b7141b6693..9f57111bf37 100644
--- a/odoo/tools/yaml_tag.py
+++ b/odoo/tools/yaml_tag.py
@@ -1,8 +1,6 @@
import yaml
import logging
-from . import pycompat
-
class YamlTag(object):
"""
@@ -16,7 +14,7 @@ class YamlTag(object):
def __getattr__(self, attr):
return None
def __repr__(self):
- return "<%s %s>" % (self.__class__.__name__, sorted(pycompat.items(self.__dict__)))
+ return "<%s %s>" % (self.__class__.__name__, sorted(self.__dict__.items()))
class Assert(YamlTag):
def __init__(self, model, id=None, severity=logging.WARNING, string="NONAME", **kwargs):