Skip to content

Commit

Permalink
[FIX] P3: list -> iterable builtins (odoo#16811)
Browse files Browse the repository at this point in the history
In Python 3:

* various builtins and dict methods were changed to return
  view/iterable objects rather than lists
* and the separate Python 2 view/iterable builtins and methods were
  removed altogether

This is problematic when using these items as list (which the happens
repeatedly in Odoo), but more viciously when iterating *multiple times*
over them (which also happens, which I've messed up multiple times while
writing this, and which is a pain to debug even when you've just created
the issue).

Convert all code using these to semantics-matching cross-version
helper functions to get the LCD behaviour between P2 and P3, and
forbid the builtins via lint.

issue odoo#8530
  • Loading branch information
xmo-odoo committed May 10, 2017
1 parent 10eee18 commit fffaf73
Show file tree
Hide file tree
Showing 237 changed files with 1,160 additions and 953 deletions.
4 changes: 2 additions & 2 deletions addons/account/models/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ def _prepare_liquidity_account(self, name, company, currency_id, type):
account_code_prefix = company.bank_account_code_prefix or ''
else:
account_code_prefix = company.cash_account_code_prefix or company.bank_account_code_prefix or ''
for num in pycompat.range(1, 100):
for num in range(1, 100):
new_code = str(account_code_prefix.ljust(code_digits - 1, '0')) + str(num)
rec = self.env['account.account'].search([('code', '=', new_code), ('company_id', '=', company.id)], limit=1)
if not rec:
Expand Down Expand Up @@ -412,7 +412,7 @@ def create(self, vals):
if not vals.get('code'):
journal_code_base = (vals['type'] == 'cash' and 'CSH' or 'BNK')
journals = self.env['account.journal'].search([('code', 'like', journal_code_base + '%'), ('company_id', '=', company_id)])
for num in pycompat.range(1, 100):
for num in range(1, 100):
# journal_code has a maximal size of 5, hence we can enforce the boundary num < 100
journal_code = journal_code_base + str(num)
if journal_code not in journals.mapped('code'):
Expand Down
4 changes: 2 additions & 2 deletions addons/account/models/account_bank_statement.py
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,7 @@ def process_reconciliations(self, data):
whose value is the same as described in process_reconciliation except that ids are used instead of recordsets.
"""
AccountMoveLine = self.env['account.move.line']
for st_line, datum in zip(self, data):
for st_line, datum in pycompat.izip(self, data):
payment_aml_rec = AccountMoveLine.browse(datum.get('payment_aml_ids', []))
for aml_dict in datum.get('counterpart_aml_dicts', []):
aml_dict['move_line'] = AccountMoveLine.browse(aml_dict['counterpart_aml_id'])
Expand Down Expand Up @@ -879,7 +879,7 @@ def process_reconciliation(self, counterpart_aml_dicts=None, payment_aml_rec=Non
for aml_dict in (counterpart_aml_dicts + new_aml_dicts):
if aml_dict.get('tax_ids') and isinstance(aml_dict['tax_ids'][0], pycompat.integer_types):
# Transform the value in the format required for One2many and Many2many fields
aml_dict['tax_ids'] = map(lambda id: (4, id, None), aml_dict['tax_ids'])
aml_dict['tax_ids'] = [(4, id, None) for id in aml_dict['tax_ids']]

# Fully reconciled moves are just linked to the bank statement
total = self.amount
Expand Down
24 changes: 12 additions & 12 deletions addons/account/models/account_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def _default_journal(self):
inv_types = inv_type if isinstance(inv_type, list) else [inv_type]
company_id = self._context.get('company_id', self.env.user.company_id.id)
domain = [
('type', 'in', filter(None, map(TYPE2JOURNAL.get, inv_types))),
('type', 'in', [TYPE2JOURNAL[ty] for ty in inv_types if ty in TYPE2JOURNAL]),
('company_id', '=', company_id),
]
return self.env['account.journal'].search(domain, limit=1)
Expand Down Expand Up @@ -192,11 +192,11 @@ def _get_payment_info_JSON(self):
@api.one
@api.depends('move_id.line_ids.amount_residual')
def _compute_payments(self):
payment_lines = []
payment_lines = set()
for line in self.move_id.line_ids:
payment_lines.extend(filter(None, [rp.credit_move_id.id for rp in line.matched_credit_ids]))
payment_lines.extend(filter(None, [rp.debit_move_id.id for rp in line.matched_debit_ids]))
self.payment_move_line_ids = self.env['account.move.line'].browse(list(set(payment_lines)))
payment_lines.update(line.mapped('matched_credit_ids.credit_move_id.id'))
payment_lines.update(line.mapped('matched_debit_ids.debit_move_id.id'))
self.payment_move_line_ids = self.env['account.move.line'].browse(list(payment_lines))

name = fields.Char(string='Reference/Description', index=True,
readonly=True, states={'draft': [('readonly', False)]}, copy=False, help='The name that will be used on account move lines')
Expand Down Expand Up @@ -335,7 +335,7 @@ def create(self, vals):
'_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 onchanges.items():
for onchange_method, changed_fields in pycompat.items(onchanges):
if any(f not in vals for f in changed_fields):
invoice = self.new(vals)
getattr(invoice, onchange_method)()
Expand Down Expand Up @@ -456,7 +456,7 @@ def compute_taxes(self):
tax_grouped = invoice.get_taxes_values()

# Create new tax lines
for tax in tax_grouped.values():
for tax in pycompat.values(tax_grouped):
account_invoice_tax.create(tax)

# dummy write on self to trigger recomputations
Expand All @@ -475,7 +475,7 @@ def unlink(self):
def _onchange_invoice_line_ids(self):
taxes_grouped = self.get_taxes_values()
tax_lines = self.tax_line_ids.browse([])
for tax in taxes_grouped.values():
for tax in pycompat.values(taxes_grouped):
tax_lines += tax_lines.new(tax)
self.tax_line_ids = tax_lines
return
Expand Down Expand Up @@ -820,7 +820,7 @@ def group_lines(self, iml, line):
else:
line2[tmp] = l
line = []
for key, val in line2.items():
for key, val in pycompat.items(line2):
line.append((0, 0, val))
return line

Expand Down Expand Up @@ -1017,7 +1017,7 @@ def _refund_cleanup_lines(self, lines):
result = []
for line in lines:
values = {}
for name, field in line._fields.iteritems():
for name, field in pycompat.items(line._fields):
if name in MAGIC_COLUMNS:
continue
elif field.type == 'many2one':
Expand Down Expand Up @@ -1155,8 +1155,8 @@ def _get_tax_amount_by_group(self):
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(res.items(), key=lambda l: l[0].sequence)
res = map(lambda l: (l[0].name, l[1]), res)
res = sorted(pycompat.items(res), key=lambda l: l[0].sequence)
res = [(l[0].name, l[1]) for l in res]
return res


Expand Down
2 changes: 1 addition & 1 deletion addons/account/models/account_journal_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ def get_journal_dashboard_datas(self):
""", (tuple(self.ids),))
number_to_reconcile = self.env.cr.fetchone()[0]
# optimization to read sum of balance from account_move_line
account_ids = tuple(filter(None, [self.default_debit_account_id.id, self.default_credit_account_id.id]))
account_ids = tuple(ac for ac in [self.default_debit_account_id.id, self.default_credit_account_id.id] if ac)
if account_ids:
amount_field = 'balance' if not self.currency_id else 'amount_currency'
query = """SELECT sum(%s) FROM account_move_line WHERE account_id in %%s;""" % (amount_field,)
Expand Down
2 changes: 1 addition & 1 deletion addons/account/models/account_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -1696,7 +1696,7 @@ def create(self, vals):
total_amount_currency += aml.company_id.currency_id.with_context(date=aml.date).compute(aml.balance, partial_rec.currency_id)
for x in aml.matched_debit_ids | aml.matched_credit_ids:
partial_rec_set[x] = None
partial_rec_ids = [x.id for x in partial_rec_set.keys()]
partial_rec_ids = [x.id for x in partial_rec_set]
aml_ids = aml_set.ids
#then, if the total debit and credit are equal, or the total amount in currency is 0, the reconciliation is full
digits_rounding_precision = aml_set[0].company_id.currency_id.rounding
Expand Down
5 changes: 4 additions & 1 deletion addons/account/models/chart_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
from odoo import SUPERUSER_ID

import logging

from odoo.tools import pycompat

_logger = logging.getLogger(__name__)

def migrate_set_tags_and_taxes_updatable(cr, registry, module):
Expand Down Expand Up @@ -322,7 +325,7 @@ def _load_template(self, company, code_digits=None, transfer_account_id=None, ac

# writing account values after creation of accounts
company.transfer_account_id = account_template_ref[transfer_account_id.id]
for key, value in generated_tax_res['account_dict'].items():
for key, value in pycompat.items(generated_tax_res['account_dict']):
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),
Expand Down
8 changes: 4 additions & 4 deletions addons/account/models/partner.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import time

from odoo import api, fields, models, _
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, pycompat
from odoo.exceptions import ValidationError
from odoo.addons.base.res.res_partner import WARNING_MESSAGE, WARNING_HELP

Expand Down Expand Up @@ -72,7 +72,7 @@ def map_accounts(self, accounts):
ref_dict = {}
for line in self.account_ids:
ref_dict[line.account_src_id] = line.account_dest_id
for key, acc in accounts.items():
for key, acc in list(pycompat.items(accounts)):
if acc in ref_dict:
accounts[key] = ref_dict[acc]
return accounts
Expand Down Expand Up @@ -245,7 +245,7 @@ def _asset_difference_search(self, account_type, operator, operand):
res = self._cr.fetchall()
if not res:
return [('id', '=', '0')]
return [('id', 'in', map(itemgetter(0), res))]
return [('id', 'in', [r[0] for r in res])]

@api.model
def _credit_search(self, operator, operand):
Expand Down Expand Up @@ -292,7 +292,7 @@ def _invoice_total(self):
""" % where_clause
self.env.cr.execute(query, where_clause_params)
price_totals = self.env.cr.dictfetchall()
for partner, child_ids in all_partners_and_children.items():
for partner, child_ids in pycompat.items(all_partners_and_children):
partner.total_invoiced = sum(price['total'] for price in price_totals if price['partner_id'] in child_ids)

@api.multi
Expand Down
2 changes: 1 addition & 1 deletion addons/account/report/account_balance.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def _get_accounts(self, accounts, display_account):
currency = account.currency_id and account.currency_id or account.company_id.currency_id
res['code'] = account.code
res['name'] = account.name
if account.id in account_result.keys():
if account.id in account_result:
res['debit'] = account_result[account.id].get('debit')
res['credit'] = account_result[account.id].get('credit')
res['balance'] = account_result[account.id].get('balance')
Expand Down
2 changes: 1 addition & 1 deletion addons/account/report/account_general_ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def _get_account_move_entry(self, accounts, init_balance, sortby, display_accoun
"""
cr = self.env.cr
MoveLine = self.env['account.move.line']
move_lines = dict(map(lambda x: (x, []), accounts.ids))
move_lines = {x: [] for x in accounts.ids}

# Prepare initial sql query and Get the initial move lines
if init_balance:
Expand Down
2 changes: 1 addition & 1 deletion addons/account/report/account_journal.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def lines(self, target_move, journal_ids, sort_selection, data):
query += 'am.name'
query += ', "account_move_line".move_id, acc.code'
self.env.cr.execute(query, tuple(params))
ids = map(lambda x: x[0], self.env.cr.fetchall())
ids = (x[0] for x in self.env.cr.fetchall())
return self.env['account.move.line'].browse(ids)

def _sum_debit(self, data, journal_id):
Expand Down
2 changes: 1 addition & 1 deletion addons/account/report/account_overdue_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class ReportOverdue(models.AbstractModel):
_name = 'report.account.report_overdue'

def _get_account_move_lines(self, partner_ids):
res = dict(map(lambda x:(x,[]), partner_ids))
res = {x: [] for x in partner_ids}
self.env.cr.execute("SELECT m.name AS move_id, l.date, l.name, l.ref, l.date_maturity, l.partner_id, l.blocked, l.amount_currency, l.currency_id, "
"CASE WHEN at.type = 'receivable' "
"THEN SUM(l.debit) "
Expand Down
19 changes: 10 additions & 9 deletions addons/account/report/account_report_financial.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import time
from odoo import api, models
from odoo.tools import pycompat


class ReportFinancial(models.AbstractModel):
Expand All @@ -18,15 +19,15 @@ def _compute_account_balance(self, accounts):

res = {}
for account in accounts:
res[account.id] = dict((fn, 0.0) for fn in mapping.keys())
res[account.id] = dict.fromkeys(mapping, 0.0)
if accounts:
tables, where_clause, where_params = self.env['account.move.line']._query_get()
tables = tables.replace('"', '') if tables else "account_move_line"
wheres = [""]
if where_clause.strip():
wheres.append(where_clause.strip())
filters = " AND ".join(wheres)
request = "SELECT account_id as id, " + ', '.join(mapping.values()) + \
request = "SELECT account_id as id, " + ', '.join(pycompat.values(mapping)) + \
" FROM " + tables + \
" WHERE account_id IN %s " \
+ filters + \
Expand All @@ -53,26 +54,26 @@ def _compute_report_balance(self, reports):
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 res[report.id]['account'].values():
for value in pycompat.values(res[report.id]['account']):
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 res[report.id]['account'].values():
for value in pycompat.values(res[report.id]['account']):
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 res2.items():
for key, value in pycompat.items(res2):
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 res2.items():
for key, value in pycompat.items(res2):
for field in fields:
res[report.id][field] += value[field]
return res
Expand All @@ -84,11 +85,11 @@ def get_account_lines(self, data):
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 comparison_res.items():
for report_id, value in pycompat.items(comparison_res):
res[report_id]['comp_bal'] = value['balance']
report_acc = res[report_id].get('account')
if report_acc:
for account_id, val in comparison_res[report_id].get('account').items():
for account_id, val in pycompat.items(comparison_res[report_id].get('account')):
report_acc[account_id]['comp_bal'] = val['balance']

for report in child_reports:
Expand All @@ -113,7 +114,7 @@ def get_account_lines(self, data):

if res[report.id].get('account'):
sub_lines = []
for account_id, value in res[report.id]['account'].items():
for account_id, value in pycompat.items(res[report.id]['account']):
#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...)
Expand Down
9 changes: 6 additions & 3 deletions addons/account/tests/test_reconciliation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
import time
import unittest

from odoo.tools import pycompat


class TestReconciliation(AccountingTestCase):

"""Tests for reconciliation (account.tax)
Expand Down Expand Up @@ -336,8 +339,8 @@ def test_balanced_exchanges_gain_loss(self):
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 result.values()]), 60.61)
self.assertEquals(sum([res['credit'] for res in result.values()]), 60.61)
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)
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:
Expand Down Expand Up @@ -473,4 +476,4 @@ def test_reconcile_bank_statement_with_payment_and_writeoff(self):
self.assertEquals(round(aml.debit, 2), line['debit'])
self.assertEquals(round(aml.credit, 2), line['credit'])
self.assertEquals(round(aml.amount_currency, 2), line['amount_currency'])
self.assertEquals(aml.currency_id.id, line['currency_id'])
self.assertEquals(aml.currency_id.id, line['currency_id'])
6 changes: 3 additions & 3 deletions addons/account_asset/models/account_asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF, pycompat
from odoo.tools import float_compare, float_is_zero


Expand Down Expand Up @@ -374,7 +374,7 @@ def onchange_category_id(self):
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 vals['value'].iteritems():
for k, v in pycompat.items(vals['value']):
setattr(self, k, v)

def onchange_category_id_values(self, category_id):
Expand Down Expand Up @@ -583,7 +583,7 @@ def _format_message(message_description, tracked_values):
message = ''
if message_description:
message = '<span>%s</span>' % message_description
for name, values in tracked_values.iteritems():
for name, values in pycompat.items(tracked_values):
message += '<div> &nbsp; &nbsp; &bull; <b>%s</b>: ' % name
message += '%s</div>' % values
return message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ def asset_compute(self):
'view_mode': 'tree,form',
'res_model': 'account.move',
'view_id': False,
'domain': "[('id','in',[" + ','.join(map(str, created_move_ids)) + "])]",
'domain': "[('id','in',[" + ','.join(str(id) for id in created_move_ids) + "])]",
'type': 'ir.actions.act_window',
}
4 changes: 2 additions & 2 deletions addons/account_test/report/report_account_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ def order_columns(item, cols=None):
:rtype: [(key, value)]
"""
if cols is None:
cols = item.keys()
return [(col, item.get(col)) for col in cols if col in item.keys()]
cols = list(item)
return [(col, item.get(col)) for col in cols if col in item]

localdict = {
'cr': self.env.cr,
Expand Down
Loading

0 comments on commit fffaf73

Please sign in to comment.