diff options
| author | Adrian Torres <adt@odoo.com> | 2018-11-08 15:27:30 +0000 |
|---|---|---|
| committer | Adrian Torres <adt@odoo.com> | 2018-11-29 09:28:17 +0000 |
| commit | 52f5528cfb6d1152ee226e268247dc685a8ba329 (patch) | |
| tree | b44ecfa477b50dd3e488f09f623eecc8bc8e9d7d | |
| parent | e5c864a596b72515837f0ed1e07550398ecc1ab0 (diff) | |
[REF] *: replace deprecated pycompat helpers for builtins
This commit replaces calls to pycompat helpers that were intended for
python 2 <-> python 3 interoperability for python 3 builtins, as python
2 is no longer officially supported by Odoo.
This includes:
* calls to imap/izip/ifilter replaced by map/zip/filter
* uses of text_type replaced by str
* uses of unichr replaced by chr
* calls to implements_to_string, implements_iterator removed
* string_types and integer_types replaced by str, int respectively
* calls to to_native replaced by calls to to_text
This is done in preparation to the removal of these deprecated helpers
in the following commit.
106 files changed, 313 insertions, 426 deletions
diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py index 46db7c5c8e7..4a2b0824d24 100644 --- a/addons/account/models/account_bank_statement.py +++ b/addons/account/models/account_bank_statement.py @@ -2,7 +2,7 @@ from odoo import api, fields, models, _ from odoo.osv import expression -from odoo.tools import float_is_zero, pycompat +from odoo.tools import float_is_zero from odoo.tools import float_compare, float_round, float_repr from odoo.tools.misc import formatLang, format_date from odoo.exceptions import UserError, ValidationError @@ -528,10 +528,10 @@ class AccountBankStatementLine(models.Model): for aml_dict in counterpart_aml_dicts: if aml_dict['move_line'].reconciled: raise UserError(_('A selected move line was already reconciled.')) - if isinstance(aml_dict['move_line'], pycompat.integer_types): + if isinstance(aml_dict['move_line'], int): aml_dict['move_line'] = aml_obj.browse(aml_dict['move_line']) 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): + if aml_dict.get('tax_ids') and isinstance(aml_dict['tax_ids'][0], int): # Transform the value in the format required for One2many and Many2many fields aml_dict['tax_ids'] = [(4, id, None) for id in aml_dict['tax_ids']] if any(line.journal_entry_ids for line in self): diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py index c0eb0808dc4..391a151e2c7 100644 --- a/addons/account/models/account_invoice.py +++ b/addons/account/models/account_invoice.py @@ -1486,7 +1486,7 @@ class AccountInvoice(models.Model): :param date: payment date, defaults to fields.Date.context_today(self) :param writeoff_acc: account in which to create a writeoff if pay_amount < self.residual, so that the invoice is fully paid """ - if isinstance(pay_journal, pycompat.integer_types): + if isinstance(pay_journal, int): pay_journal = self.env['account.journal'].browse([pay_journal]) assert len(self) == 1, "Can only pay one invoice at a time." diff --git a/addons/account/models/chart_template.py b/addons/account/models/chart_template.py index 4c5c9645fef..1bed913ba37 100644 --- a/addons/account/models/chart_template.py +++ b/addons/account/models/chart_template.py @@ -4,7 +4,6 @@ from odoo.exceptions import AccessError from odoo import api, fields, models, _ from odoo import SUPERUSER_ID from odoo.exceptions import UserError -from odoo.tools import pycompat import logging @@ -592,7 +591,7 @@ class AccountChartTemplate(models.Model): # regular accounts created and that liquidity transfer account records = super(AccountChartTemplate, self)._load_records(data_list, update) account_data_list = [] - for data, record in pycompat.izip(data_list, records): + for data, record in zip(data_list, records): # Create the transfer account only for leaf chart template in the hierarchy. if record.parent_id: continue @@ -652,7 +651,7 @@ class AccountChartTemplate(models.Model): vals = self._get_account_vals(company, account_template, code_acc, tax_template_ref) template_vals.append((account_template, vals)) accounts = self._create_records_with_xmlid('account.account', template_vals, company) - for template, account in pycompat.izip(acc_template, accounts): + for template, account in zip(acc_template, accounts): acc_template_ref[template.id] = account.id return acc_template_ref @@ -752,7 +751,7 @@ class AccountChartTemplate(models.Model): # then create fiscal position taxes and accounts tax_template_vals = [] account_template_vals = [] - for position, fp in pycompat.izip(positions, fps): + for position, fp in zip(positions, fps): for tax in position.tax_ids: tax_template_vals.append((tax, { 'tax_src_id': tax_template_ref[tax.tax_src_id.id], @@ -893,7 +892,7 @@ class AccountTaxTemplate(models.Model): taxes = ChartTemplate._create_records_with_xmlid('account.tax', template_vals, company) # fill in tax_template_to_tax and todo_dict - for tax, (template, vals) in pycompat.izip(taxes, template_vals): + for tax, (template, vals) in zip(taxes, template_vals): tax_template_to_tax[template.id] = tax.id # Since the accounts have not been created yet, we have to wait before filling these fields todo_dict[tax.id] = { diff --git a/addons/account/models/reconciliation_widget.py b/addons/account/models/reconciliation_widget.py index 934272c1c81..65f3992c3ba 100644 --- a/addons/account/models/reconciliation_widget.py +++ b/addons/account/models/reconciliation_widget.py @@ -3,7 +3,6 @@ from odoo import api, fields, models, _ from odoo.exceptions import UserError from odoo.osv import expression -from odoo.tools import pycompat from odoo.tools.misc import formatLang @@ -30,7 +29,7 @@ class AccountReconciliation(models.AbstractModel): AccountMoveLine = self.env['account.move.line'] ctx = dict(self._context, force_price_include=False) - for st_line, datum in pycompat.izip(st_lines, data): + for st_line, datum in zip(st_lines, data): payment_aml_rec = AccountMoveLine.browse(datum.get('payment_aml_ids', [])) for aml_dict in datum.get('counterpart_aml_dicts', []): diff --git a/addons/account_facturx/models/account_invoice.py b/addons/account_facturx/models/account_invoice.py index b6a649542c5..619bd64d354 100644 --- a/addons/account_facturx/models/account_invoice.py +++ b/addons/account_facturx/models/account_invoice.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from odoo import api, models, fields, tools, _ -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, pycompat, float_repr +from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, float_repr from odoo.tests.common import Form from datetime import datetime @@ -249,7 +249,7 @@ class AccountInvoice(models.Model): # ['file.xml', {'/Type': '/Filespec', '/F': 'file.xml', '/EF': {'/F': IndirectObject(22, 0)}}] embedded_files = reader.trailer['/Root']['/Names']['/EmbeddedFiles']['/Names'] # '[::2]' because it's a list [fn_1, content_1, fn_2, content_2, ..., fn_n, content_2] - for filename_obj, content_obj in list(pycompat.izip(embedded_files, embedded_files[1:]))[::2]: + for filename_obj, content_obj in list(zip(embedded_files, embedded_files[1:]))[::2]: content = content_obj.getObject()['/EF']['/F'].getData() if filename_obj == 'factur-x.xml': diff --git a/addons/auth_ldap/models/res_company_ldap.py b/addons/auth_ldap/models/res_company_ldap.py index 54f5dda89e6..7f36b1ba2dc 100644 --- a/addons/auth_ldap/models/res_company_ldap.py +++ b/addons/auth_ldap/models/res_company_ldap.py @@ -7,7 +7,7 @@ from ldap.filter import filter_format from odoo import _, api, fields, models, tools from odoo.exceptions import AccessDenied -from odoo.tools.pycompat import to_native +from odoo.tools.pycompat import to_text _logger = logging.getLogger(__name__) @@ -109,7 +109,7 @@ class CompanyLDAP(models.Model): if len(results) == 1: dn = results[0][0] conn = self._connect(conf) - conn.simple_bind_s(dn, to_native(password)) + conn.simple_bind_s(dn, to_text(password)) conn.unbind() entry = results[0] except ldap.INVALID_CREDENTIALS: @@ -146,8 +146,8 @@ class CompanyLDAP(models.Model): conn = self._connect(conf) ldap_password = conf['ldap_password'] or '' ldap_binddn = conf['ldap_binddn'] or '' - conn.simple_bind_s(to_native(ldap_binddn), to_native(ldap_password)) - results = conn.search_st(to_native(conf['ldap_base']), ldap.SCOPE_SUBTREE, filter, retrieve_attributes, timeout=60) + conn.simple_bind_s(to_text(ldap_binddn), to_text(ldap_password)) + results = conn.search_st(to_text(conf['ldap_base']), ldap.SCOPE_SUBTREE, filter, retrieve_attributes, timeout=60) conn.unbind() except ldap.INVALID_CREDENTIALS: _logger.error('LDAP bind failed.') diff --git a/addons/base_import/models/base_import.py b/addons/base_import/models/base_import.py index 35d5692e95b..d6c05217bc9 100644 --- a/addons/base_import/models/base_import.py +++ b/addons/base_import/models/base_import.py @@ -263,15 +263,15 @@ class Import(models.TransientModel): def _read_xls_book(self, book): sheet = book.sheet_by_index(0) # emulate Sheet.get_rows for pre-0.9.4 - for row in pycompat.imap(sheet.row, range(sheet.nrows)): + for row in map(sheet.row, range(sheet.nrows)): values = [] for cell in row: if cell.ctype is xlrd.XL_CELL_NUMBER: is_float = cell.value % 1 != 0.0 values.append( - pycompat.text_type(cell.value) + str(cell.value) if is_float - else pycompat.text_type(int(cell.value)) + else str(int(cell.value)) ) elif cell.ctype is xlrd.XL_CELL_DATE: is_datetime = cell.value % 1 != 0.0 @@ -642,7 +642,7 @@ class Import(models.TransientModel): if options.get('headers'): rows_to_import = itertools.islice(rows_to_import, 1, None) data = [ - list(row) for row in pycompat.imap(mapper, rows_to_import) + list(row) for row in map(mapper, rows_to_import) # don't try inserting completely empty rows (e.g. from # filtering out o2m fields) if any(row) @@ -863,7 +863,7 @@ class Import(models.TransientModel): return { 'messages': [{ 'type': 'error', - 'message': pycompat.text_type(error), + 'message': str(error), 'record': False, }] } diff --git a/addons/base_import_module/models/ir_module.py b/addons/base_import_module/models/ir_module.py index 425ad1a01f4..128594cc824 100644 --- a/addons/base_import_module/models/ir_module.py +++ b/addons/base_import_module/models/ir_module.py @@ -11,7 +11,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__) @@ -88,7 +88,7 @@ class IrModule(models.Model): with open(full_path, 'rb') as fp: data = base64.b64encode(fp.read()) url_path = '/{}{}'.format(module, full_path.split(path)[1].replace(os.path.sep, '/')) - if not isinstance(url_path, pycompat.text_type): + if not isinstance(url_path, str): url_path = url_path.decode(sys.getfilesystemencoding()) filename = os.path.split(url_path)[1] values = dict( diff --git a/addons/board/models/board.py b/addons/board/models/board.py index cb876d61330..a3355755b2f 100644 --- a/addons/board/models/board.py +++ b/addons/board/models/board.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 Board(models.AbstractModel): diff --git a/addons/bus/controllers/main.py b/addons/bus/controllers/main.py index bdbdd47096b..a5a0e3e189b 100644 --- a/addons/bus/controllers/main.py +++ b/addons/bus/controllers/main.py @@ -4,8 +4,6 @@ from odoo import exceptions, _ from odoo.http import Controller, request, route from odoo.addons.bus.models.bus import dispatch -from odoo.tools import pycompat - class BusController(Controller): """ Examples: @@ -16,7 +14,7 @@ class BusController(Controller): @route('/longpolling/send', type="json", auth="public") def send(self, channel, message): - if not isinstance(channel, pycompat.string_types): + if not isinstance(channel, str): raise Exception("bus.Bus only string channels are allowed.") return request.env['bus.bus'].sendone(channel, message) @@ -35,7 +33,7 @@ class BusController(Controller): options = {} if not dispatch: raise Exception("bus.Bus unavailable") - if [c for c in channels if not isinstance(c, pycompat.string_types)]: + if [c for c in channels if not isinstance(c, str)]: raise Exception("bus.Bus only string channels are allowed.") if request.registry.in_test_mode(): raise exceptions.UserError(_("bus.Bus not available in test mode")) diff --git a/addons/bus/models/bus.py b/addons/bus/models/bus.py index d5d84fa77d2..7a7f8b497db 100644 --- a/addons/bus/models/bus.py +++ b/addons/bus/models/bus.py @@ -117,8 +117,7 @@ class ImDispatch(object): # it will handle a longpolling request if not odoo.evented: current = threading.current_thread() - current._Thread__daemonic = True # PY2 - current._daemonic = True # PY3 + current._daemonic = True # rename the thread to avoid tests waiting for a longpolling current.setName("openerp.longpolling.request.%s" % current.ident) diff --git a/addons/calendar/models/calendar.py b/addons/calendar/models/calendar.py index f0986c096e0..bb6c41ab8ac 100644 --- a/addons/calendar/models/calendar.py +++ b/addons/calendar/models/calendar.py @@ -35,7 +35,7 @@ def calendar_id2real_id(calendar_id=None, with_date=False): :param with_date: if a value is passed to this param it will return dates based on value of withdate + calendar_id :return: real event id """ - if calendar_id and isinstance(calendar_id, pycompat.string_types): + if calendar_id and isinstance(calendar_id, str): res = [bit for bit in calendar_id.split('-') if bit] if len(res) == 2: real_id = res[0] @@ -49,7 +49,7 @@ def calendar_id2real_id(calendar_id=None, with_date=False): def get_real_ids(ids): - if isinstance(ids, (pycompat.string_types, pycompat.integer_types)): + if isinstance(ids, (str, int)): return calendar_id2real_id(ids) if isinstance(ids, (list, tuple)): @@ -71,7 +71,7 @@ def any_id2key(record_id): :type record_id: int | str :rtype: (int, str) """ - if isinstance(record_id, pycompat.integer_types): + if isinstance(record_id, int): return record_id, u'' (real_id, virtual_id) = record_id.split('-') @@ -587,7 +587,7 @@ class Meeting(models.Model): """ Get recurrent start and stop dates based on Rule string""" start_dates = self._get_recurrent_date_by_event(date_field='start') stop_dates = self._get_recurrent_date_by_event(date_field='stop') - return list(pycompat.izip(start_dates, stop_dates)) + return list(zip(start_dates, stop_dates)) @api.multi def _get_recurrent_date_by_event(self, date_field='start'): @@ -697,9 +697,8 @@ class Meeting(models.Model): 'time_format': record_lang.time_format } - # formats will be used for str{f,p}time() which do not support unicode in Python 2, coerce to str - format_date = pycompat.to_native(lang_params.get("date_format", '%B-%d-%Y')) - format_time = pycompat.to_native(lang_params.get("time_format", '%I-%M %p')) + format_date = lang_params.get("date_format", '%B-%d-%Y') + format_time = lang_params.get("time_format", '%I-%M %p') return (format_date, format_time) @api.model @@ -715,7 +714,6 @@ class Meeting(models.Model): 2) if event all day ,return : AllDay, July-31-2013 """ timezone = self._context.get('tz') or self.env.user.partner_id.tz or 'UTC' - timezone = pycompat.to_native(timezone) # make safe for str{p,f}time() # get date/time format according to context format_date, format_time = self._get_date_formats() @@ -1188,7 +1186,7 @@ class Meeting(models.Model): pile.reverse() new_pile = [] for item in pile: - if not isinstance(item, pycompat.string_types): + if not isinstance(item, str): res = item elif str(item) == str('&'): first = new_pile.pop() @@ -1355,7 +1353,7 @@ class Meeting(models.Model): if interval == 'day': # Day number (1-31) - result = pycompat.text_type(date.day) + result = str(date.day) elif interval == 'month': # Localized month name and year @@ -1468,7 +1466,7 @@ class Meeting(models.Model): @api.returns('mail.message', lambda value: value.id) def message_post(self, **kwargs): thread_id = self.id - if isinstance(self.id, pycompat.string_types): + if isinstance(self.id, str): thread_id = get_real_ids(self.id) if self.env.context.get('default_date'): context = dict(self.env.context) @@ -1505,7 +1503,7 @@ class Meeting(models.Model): for arg in args: if arg[0] == 'id': for n, calendar_id in enumerate(arg[2]): - if isinstance(calendar_id, pycompat.string_types): + if isinstance(calendar_id, str): arg[2][n] = calendar_id.split('-')[0] return super(Meeting, self)._name_search(name=name, args=args, operator=operator, limit=limit, name_get_uid=name_get_uid) @@ -1661,7 +1659,7 @@ class Meeting(models.Model): continue res = real_data[real_id].copy() ls = calendar_id2real_id(calendar_id, with_date=res and res.get('duration', 0) > 0 and res.get('duration') or 1) - if not isinstance(ls, (pycompat.string_types, pycompat.integer_types)) and len(ls) >= 2: + if not isinstance(ls, (str, int)) and len(ls) >= 2: res['start'] = ls[1] res['stop'] = ls[2] diff --git a/addons/calendar/models/ir_attachment.py b/addons/calendar/models/ir_attachment.py index b19f752a507..ae1fe6aafb9 100644 --- a/addons/calendar/models/ir_attachment.py +++ b/addons/calendar/models/ir_attachment.py @@ -5,8 +5,6 @@ from odoo import api, models from odoo.addons.calendar.models.calendar import get_real_ids -from odoo.tools import pycompat - class Attachment(models.Model): @@ -18,13 +16,13 @@ class Attachment(models.Model): args = list(args) if any([leaf for leaf in args if leaf[0] == "res_model" and leaf[2] == 'calendar.event']): for index in range(len(args)): - if args[index][0] == "res_id" and isinstance(args[index][2], pycompat.string_types): + if args[index][0] == "res_id" and isinstance(args[index][2], str): args[index] = (args[index][0], args[index][1], get_real_ids(args[index][2])) return super(Attachment, self)._search(args, offset=offset, limit=limit, order=order, count=count, access_rights_uid=access_rights_uid) @api.multi def write(self, vals): """ When posting an attachment (new or not), convert the virtual ids in real ids. """ - if isinstance(vals.get('res_id'), pycompat.string_types): + if isinstance(vals.get('res_id'), str): vals['res_id'] = get_real_ids(vals.get('res_id')) return super(Attachment, self).write(vals) diff --git a/addons/calendar/models/mail_message.py b/addons/calendar/models/mail_message.py index 426c7a78d52..cd8ed5d89ae 100644 --- a/addons/calendar/models/mail_message.py +++ b/addons/calendar/models/mail_message.py @@ -5,8 +5,6 @@ from odoo import api, models from odoo.addons.calendar.models.calendar import get_real_ids -from odoo.tools import pycompat - class Message(models.Model): @@ -18,7 +16,7 @@ class Message(models.Model): args = list(args) for index in range(len(args)): if args[index][0] == "res_id": - if isinstance(args[index][2], pycompat.string_types): + if isinstance(args[index][2], str): args[index] = (args[index][0], args[index][1], get_real_ids(args[index][2])) elif isinstance(args[index][2], list): args[index] = (args[index][0], args[index][1], [get_real_ids(x) for x in args[index][2]]) diff --git a/addons/gamification/models/goal.py b/addons/gamification/models/goal.py index a44d562500b..dba9d63a329 100644 --- a/addons/gamification/models/goal.py +++ b/addons/gamification/models/goal.py @@ -7,7 +7,6 @@ from datetime import date, datetime, timedelta from odoo import api, fields, models, _, exceptions from odoo.osv import expression -from odoo.tools import pycompat from odoo.tools.safe_eval import safe_eval _logger = logging.getLogger(__name__) @@ -285,7 +284,7 @@ class Goal(models.Model): safe_eval(code, cxt, mode="exec", nocopy=True) # the result of the evaluated codeis put in the 'result' local variable, propagated to the context result = cxt.get('result') - if result is not None and isinstance(result, (float, pycompat.integer_types)): + if isinstance(result, (float, int)): goals_to_write.update(goal._get_write_values(result)) else: _logger.error( @@ -326,7 +325,7 @@ class Goal(models.Model): for goal in [g for g in goals if g.id in query_goals]: for user_value in user_values: queried_value = field_name in user_value and user_value[field_name] or False - if isinstance(queried_value, tuple) and len(queried_value) == 2 and isinstance(queried_value[0], pycompat.integer_types): + if isinstance(queried_value, tuple) and len(queried_value) == 2 and isinstance(queried_value[0], int): queried_value = queried_value[0] if queried_value == query_goals[goal.id]: new_value = user_value.get(field_name+'_count', goal.current) diff --git a/addons/google_drive/models/google_drive.py b/addons/google_drive/models/google_drive.py index f65616c31d4..58191842aaa 100644 --- a/addons/google_drive/models/google_drive.py +++ b/addons/google_drive/models/google_drive.py @@ -9,7 +9,6 @@ import werkzeug.urls from odoo import api, fields, models from odoo.exceptions import RedirectWarning, UserError -from odoo.tools import pycompat from odoo.tools.safe_eval import safe_eval from odoo.tools.translate import _ @@ -155,7 +154,7 @@ class GoogleDrive(models.Model): :return: the config id and config name ''' # TO DO in master: fix my signature and my model - if isinstance(res_model, pycompat.string_types): + if isinstance(res_model, str): res_model = self.env['ir.model'].search([('model', '=', res_model)]).id if not res_id: raise UserError(_("Creating google drive may only be done by one at a time.")) diff --git a/addons/hw_escpos/escpos/escpos.py b/addons/hw_escpos/escpos/escpos.py index 0369aa2a0a4..a92b0d44eb1 100644 --- a/addons/hw_escpos/escpos/escpos.py +++ b/addons/hw_escpos/escpos/escpos.py @@ -13,7 +13,6 @@ from hashlib import md5 from PIL import Image from xml.etree import ElementTree as ET -from odoo.tools import pycompat try: import jcconv @@ -30,7 +29,7 @@ from .exceptions import * def utfstr(stuff): """ converts stuff to string and does without failing if stuff is a utf8 string """ - if isinstance(stuff,pycompat.string_types): + if isinstance(stuff, str): return stuff else: return str(stuff) diff --git a/addons/l10n_ch/models/mail_template.py b/addons/l10n_ch/models/mail_template.py index b089d0b5f86..e3a1deca1dd 100644 --- a/addons/l10n_ch/models/mail_template.py +++ b/addons/l10n_ch/models/mail_template.py @@ -4,7 +4,6 @@ import base64 from odoo import api, models -from odoo.tools import pycompat class MailTemplate(models.Model): @@ -21,7 +20,7 @@ class MailTemplate(models.Model): rslt = super(MailTemplate, self).generate_email(res_ids, fields) multi_mode = True - if isinstance(res_ids, pycompat.integer_types): + if isinstance(res_ids, int): res_ids = [res_ids] multi_mode = False diff --git a/addons/l10n_lu/scripts/tax2csv.py b/addons/l10n_lu/scripts/tax2csv.py index 23fec3c734c..2a2da358b4b 100644 --- a/addons/l10n_lu/scripts/tax2csv.py +++ b/addons/l10n_lu/scripts/tax2csv.py @@ -26,7 +26,7 @@ class LuxTaxGenerator: yield keys for i in range(1, self.sheet_tax_codes.nrows): row = (c.value for c in self.sheet_tax_codes.row(i)) - d = OrderedDict(pycompat.izip(keys, row)) + d = OrderedDict(zip(keys, row)) d['sign'] = int(d['sign']) d['sequence'] = int(d['sequence']) yield d @@ -36,14 +36,14 @@ class LuxTaxGenerator: yield keys for i in range(1, self.sheet_taxes.nrows): row = (c.value for c in self.sheet_taxes.row(i)) - yield OrderedDict(pycompat.izip(keys, row)) + yield OrderedDict(zip(keys, row)) def iter_fiscal_pos_map(self): keys = [c.value for c in self.sheet_fiscal_pos_map.row(0)] yield keys for i in range(1, self.sheet_fiscal_pos_map.nrows): row = (c.value for c in self.sheet_fiscal_pos_map.row(i)) - yield OrderedDict(pycompat.izip(keys, row)) + yield OrderedDict(zip(keys, row)) def tax_codes_to_csv(self): writer = pycompat.csv_writer(open('account.tax.code.template-%s.csv' % diff --git a/addons/mail/controllers/main.py b/addons/mail/controllers/main.py index 7a9d6b82838..6694fbf72b1 100644 --- a/addons/mail/controllers/main.py +++ b/addons/mail/controllers/main.py @@ -12,7 +12,7 @@ from odoo import api, http, registry, SUPERUSER_ID, _ from odoo.addons.web.controllers.main import binary_content from odoo.exceptions import AccessError from odoo.http import request -from odoo.tools import consteq, pycompat +from odoo.tools import consteq _logger = logging.getLogger(__name__) @@ -192,7 +192,7 @@ class MailController(http.Controller): model, res_id = message.model, message.res_id # ============================================================================================== - if res_id and isinstance(res_id, pycompat.string_types): + if res_id and isinstance(res_id, str): res_id = int(res_id) return self._redirect_to_record(model, res_id, access_token, **kwargs) diff --git a/addons/mail/models/ir_model.py b/addons/mail/models/ir_model.py index 0b029f3e1a1..b85a6adae3e 100644 --- a/addons/mail/models/ir_model.py +++ b/addons/mail/models/ir_model.py @@ -3,7 +3,6 @@ from odoo import _, api, fields, models from odoo.exceptions import UserError -from odoo.tools import pycompat class IrModel(models.Model): @@ -48,7 +47,7 @@ class IrModel(models.Model): model_class = super(IrModel, self)._instanciate(model_data) if model_data.get('is_mail_thread') and model_class._name != 'mail.thread': parents = model_class._inherit or [] - parents = [parents] if isinstance(parents, pycompat.string_types) else parents + parents = [parents] if isinstance(parents, str) else parents model_class._inherit = parents + ['mail.thread'] return model_class diff --git a/addons/mail/models/mail_activity.py b/addons/mail/models/mail_activity.py index d7829ae0a1a..b925f59b1be 100644 --- a/addons/mail/models/mail_activity.py +++ b/addons/mail/models/mail_activity.py @@ -9,7 +9,6 @@ import pytz from odoo import api, exceptions, fields, models, _ -from odoo.tools import pycompat from odoo.tools.misc import clean_context _logger = logging.getLogger(__name__) @@ -657,7 +656,7 @@ class MailActivityMixin(models.AbstractModel): return False render_context = render_context or dict() - if isinstance(views_or_xmlid, pycompat.string_types): + if isinstance(views_or_xmlid, str): views = self.env.ref(views_or_xmlid, raise_if_not_found=False) else: views = views_or_xmlid diff --git a/addons/mail/models/mail_blacklist.py b/addons/mail/models/mail_blacklist.py index 919d3c20823..0329bea96d6 100644 --- a/addons/mail/models/mail_blacklist.py +++ b/addons/mail/models/mail_blacklist.py @@ -62,7 +62,7 @@ class MailBlackList(models.Model): if args: new_args = [] for arg in args: - if isinstance(arg, (list, tuple)) and arg[0] == 'email' and isinstance(arg[2], tools.pycompat.text_type): + if isinstance(arg, (list, tuple)) and arg[0] == 'email' and isinstance(arg[2], str): normalized = tools.email_normalize(arg[2]) if normalized: new_args.append([arg[0], arg[1], normalized]) diff --git a/addons/mail/models/mail_channel.py b/addons/mail/models/mail_channel.py index b9cb878d393..cd0e9778e45 100644 --- a/addons/mail/models/mail_channel.py +++ b/addons/mail/models/mail_channel.py @@ -11,7 +11,7 @@ from uuid import uuid4 from odoo import _, api, fields, models, modules, tools from odoo.exceptions import UserError, ValidationError from odoo.osv import expression -from odoo.tools import ormcache, pycompat +from odoo.tools import ormcache from odoo.tools.safe_eval import safe_eval MODERATION_FIELDS = ['moderation', 'moderator_ids', 'moderation_ids', 'moderation_notify', 'moderation_notify_msg', 'moderation_guidelines', 'moderation_guidelines_msg'] @@ -357,7 +357,7 @@ class Channel(models.Model): email = '' if self.moderation and message_type in ['email', 'comment']: author_id = kwargs.get('author_id') - if author_id and isinstance(author_id, pycompat.integer_types): + if author_id and isinstance(author_id, int): email = self.env['res.partner'].browse([author_id]).email elif author_id: email = author_id.email diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py index 4f3689ba99b..80cc1507357 100644 --- a/addons/mail/models/mail_template.py +++ b/addons/mail/models/mail_template.py @@ -14,7 +14,6 @@ from werkzeug import urls from odoo import _, api, fields, models, tools from odoo.exceptions import UserError -from odoo.tools import pycompat _logger = logging.getLogger(__name__) @@ -45,7 +44,7 @@ def format_tz(env, dt, tz=False, format=False): return format_datetime(ts, format or 'medium', locale=env.context.get("lang") or 'en_US') if format: - return pycompat.text_type(ts.strftime(format)) + return str(ts.strftime(format)) else: lang = env.context.get("lang") langs = env['res.lang'] @@ -54,9 +53,9 @@ def format_tz(env, dt, tz=False, format=False): format_date = langs.date_format or '%B-%d-%Y' format_time = langs.time_format or '%I-%M %p' - fdate = pycompat.text_type(ts.strftime(format_date)) - ftime = pycompat.text_type(ts.strftime(format_time)) - return u"%s %s%s" % (fdate, ftime, (u' (%s)' % tz) if tz else u'') + fdate = ts.strftime(format_date) + ftime = ts.strftime(format_time) + return "%s %s%s" % (fdate, ftime, (' (%s)' % tz) if tz else '') def format_amount(env, amount, currency): fmt = "%.{0}f".format(currency.decimal_places) @@ -303,7 +302,7 @@ class MailTemplate(models.Model): :param int res_ids: list of ids of document records those mails are related to. """ multi_mode = True - if isinstance(res_ids, pycompat.integer_types): + if isinstance(res_ids, int): multi_mode = False res_ids = [res_ids] @@ -349,7 +348,7 @@ class MailTemplate(models.Model): @api.multi def get_email_template(self, res_ids): multi_mode = True - if isinstance(res_ids, pycompat.integer_types): + if isinstance(res_ids, int): res_ids = [res_ids] multi_mode = False @@ -413,7 +412,7 @@ class MailTemplate(models.Model): """ self.ensure_one() multi_mode = True - if isinstance(res_ids, pycompat.integer_types): + if isinstance(res_ids, int): res_ids = [res_ids] multi_mode = False if fields is None: diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index 3149780e926..b950cf756e3 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -277,7 +277,7 @@ class MailThread(models.AbstractModel): thread._message_log(body=_('%s created') % doc_name) # auto_subscribe: take values and defaults into account - for thread, values in pycompat.izip(threads, vals_list): + for thread, values in zip(threads, vals_list): create_values = dict(values) for key, val in self._context.items(): if key.startswith('default_') and key[8:] not in create_values: @@ -290,7 +290,7 @@ class MailThread(models.AbstractModel): track_threads = threads.with_context(lang=self.env.user.lang) else: track_threads = threads - for thread, values in pycompat.izip(track_threads, vals_list): + for thread, values in zip(track_threads, vals_list): tracked_fields = thread._get_tracked_fields(list(values)) if tracked_fields: initial_values = {thread.id: dict.fromkeys(tracked_fields, False)} @@ -578,7 +578,7 @@ class MailThread(models.AbstractModel): for field_name, (template, post_kwargs) in templates.items(): if not template: continue - if isinstance(template, pycompat.string_types): + if isinstance(template, str): self.message_post_with_view(template, **post_kwargs) else: self.message_post_with_template(template.id, **post_kwargs) @@ -1388,15 +1388,9 @@ class MailThread(models.AbstractModel): # convert it to utf-8 for transport between the mailgate script and here. if isinstance(message, xmlrpclib.Binary): message = bytes(message.data) - # message_from_string parses from a *native string*, except apparently - # sometimes message is ISO-8859-1 binary data or some shit and the - # straightforward version (pycompat.to_native) won't work right -> - # always encode message to bytes then use the relevant method - # depending on ~python version - if isinstance(message, pycompat.text_type): + if isinstance(message, str): message = message.encode('utf-8') - extract = getattr(email, 'message_from_bytes', email.message_from_string) - msg_txt = extract(message) + msg_txt = email.message_from_bytes(message) # parse the message, verify we are not in a loop by checking message_id is not duplicated msg = self.message_parse(msg_txt, save_original=save_original) @@ -1510,8 +1504,7 @@ class MailThread(models.AbstractModel): for node in to_remove: node.getparent().remove(node) if postprocessed: - body = etree.tostring(root, pretty_print=False, encoding='UTF-8') - body = pycompat.to_native(body) + body = etree.tostring(root, pretty_print=False, encoding='unicode') return body, attachments def _message_extract_payload(self, message, save_original=False): @@ -1623,7 +1616,7 @@ class MailThread(models.AbstractModel): } if not isinstance(message, Message): # message_from_string works on a native str - message = pycompat.to_native(message) + message = pycompat.to_text(message) message = email.message_from_string(message) message_id = message['message-id'] @@ -1883,7 +1876,7 @@ class MailThread(models.AbstractModel): cid = info and info.get('cid') else: continue - if isinstance(content, pycompat.text_type): + if isinstance(content, str): content = content.encode('utf-8') elif content is None: continue @@ -1977,7 +1970,7 @@ class MailThread(models.AbstractModel): partner_ids.add(partner_id[1]) if isinstance(partner_id, (list, tuple)) and partner_id[0] == 6 and len(partner_id) == 3: partner_ids |= set(partner_id[2]) - elif isinstance(partner_id, pycompat.integer_types): + elif isinstance(partner_id, int): partner_ids.add(partner_id) else: pass # we do not manage anything else @@ -2097,7 +2090,7 @@ class MailThread(models.AbstractModel): values['slug'] = slug except ImportError: values['slug'] = lambda self: self.id - if isinstance(views_or_xmlid, pycompat.string_types): + if isinstance(views_or_xmlid, str): views = self.env.ref(views_or_xmlid, raise_if_not_found=False) else: views = views_or_xmlid diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index b9a5845896c..c2ef637d299 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -5,7 +5,6 @@ import base64 import re from odoo import _, api, fields, models, SUPERUSER_ID, tools -from odoo.tools import pycompat from odoo.tools.safe_eval import safe_eval @@ -453,7 +452,7 @@ class MailComposer(models.TransientModel): """ self.ensure_one() multi_mode = True - if isinstance(res_ids, pycompat.integer_types): + if isinstance(res_ids, int): multi_mode = False res_ids = [res_ids] @@ -503,7 +502,7 @@ class MailComposer(models.TransientModel): """ Call email_template.generate_email(), get fields relevant for mail.compose.message, transform email_cc and email_to into partner_ids """ multi_mode = True - if isinstance(res_ids, pycompat.integer_types): + if isinstance(res_ids, int): multi_mode = False res_ids = [res_ids] diff --git a/addons/payment_adyen/models/payment.py b/addons/payment_adyen/models/payment.py index 6ed0c938e08..a18bd385f50 100644 --- a/addons/payment_adyen/models/payment.py +++ b/addons/payment_adyen/models/payment.py @@ -14,7 +14,7 @@ from werkzeug import urls 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.pycompat import to_native +from odoo.tools.pycompat import to_text _logger = logging.getLogger(__name__) @@ -193,7 +193,7 @@ class TxAdyen(models.Model): shasign_check = tx.acquirer_id._adyen_generate_merchant_sig_sha256('out', data) else: shasign_check = tx.acquirer_id._adyen_generate_merchant_sig('out', data) - if to_native(shasign_check) != to_native(data.get('merchantSig')): + if to_text(shasign_check) != to_text(data.get('merchantSig')): error_msg = _('Adyen: invalid merchantSig, received %s, computed %s') % (data.get('merchantSig'), shasign_check) _logger.warning(error_msg) raise ValidationError(error_msg) diff --git a/addons/point_of_sale/tests/test_point_of_sale_flow.py b/addons/point_of_sale/tests/test_point_of_sale_flow.py index 9b77988337c..d76c660d0fc 100644 --- a/addons/point_of_sale/tests/test_point_of_sale_flow.py +++ b/addons/point_of_sale/tests/test_point_of_sale_flow.py @@ -3,7 +3,7 @@ import time import odoo from odoo import fields -from odoo.tools import float_compare, mute_logger, test_reports, pycompat +from odoo.tools import float_compare, mute_logger, test_reports from odoo.addons.point_of_sale.tests.common import TestPointOfSaleCommon @@ -665,9 +665,9 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): debit_lines = self.pos_order_pos0.account_move.mapped('line_ids.debit') credit_lines = self.pos_order_pos0.account_move.mapped('line_ids.credit') amount_currency_lines = self.pos_order_pos0.account_move.mapped('line_ids.amount_currency') - for a, b in pycompat.izip(sorted(debit_lines), [0.0, 0.0, 0.0, 0.0, 879.55]): + for a, b in zip(sorted(debit_lines), [0.0, 0.0, 0.0, 0.0, 879.55]): self.assertAlmostEqual(a, b) - for a, b in pycompat.izip(sorted(credit_lines), [0.0, 22.5, 40.91, 388.64, 427.5]): + for a, b in zip(sorted(credit_lines), [0.0, 22.5, 40.91, 388.64, 427.5]): self.assertAlmostEqual(a, b) - for a, b in pycompat.izip(sorted(amount_currency_lines), [-855.0, -777.27, -81.82, -45.0, 1752.75]): + for a, b in zip(sorted(amount_currency_lines), [-855.0, -777.27, -81.82, -45.0, 1752.75]): self.assertAlmostEqual(a, b) diff --git a/addons/product/models/product.py b/addons/product/models/product.py index 990090b4218..a564a79dda4 100644 --- a/addons/product/models/product.py +++ b/addons/product/models/product.py @@ -9,7 +9,7 @@ from odoo.osv import expression from odoo.addons import decimal_precision as dp -from odoo.tools import float_compare, pycompat +from odoo.tools import float_compare class ProductCategory(models.Model): @@ -165,11 +165,11 @@ class ProductProduct(models.Model): quantity = self._context.get('quantity', 1.0) # Support context pricelists specified as display_name or ID for compatibility - if isinstance(pricelist_id_or_name, pycompat.string_types): + if isinstance(pricelist_id_or_name, str): pricelist_name_search = self.env['product.pricelist'].name_search(pricelist_id_or_name, operator='=', limit=1) if pricelist_name_search: pricelist = self.env['product.pricelist'].browse([pricelist_name_search[0][0]]) - elif isinstance(pricelist_id_or_name, pycompat.integer_types): + elif isinstance(pricelist_id_or_name, int): pricelist = self.env['product.pricelist'].browse(pricelist_id_or_name) if pricelist: @@ -268,7 +268,7 @@ class ProductProduct(models.Model): @api.one def _set_image_value(self, value): - if isinstance(value, pycompat.text_type): + if isinstance(value, str): value = value.encode('ascii') image = tools.image_resize_image_big(value) if self.product_tmpl_id.image: @@ -308,7 +308,7 @@ class ProductProduct(models.Model): @api.model_create_multi def create(self, vals_list): products = super(ProductProduct, self.with_context(create_product_product=True)).create(vals_list) - for product, vals in pycompat.izip(products, vals_list): + for product, vals in zip(products, vals_list): # When a unique variant is created from tmpl then the standard price is set by _set_standard_price if not (self.env.context.get('create_from_tmpl') and len(product.product_tmpl_id.product_variant_ids) == 1): product._set_standard_price(vals.get('standard_price') or 0.0) diff --git a/addons/product/models/product_pricelist.py b/addons/product/models/product_pricelist.py index bec6eb8fdcf..4cae61d9a0b 100644 --- a/addons/product/models/product_pricelist.py +++ b/addons/product/models/product_pricelist.py @@ -8,8 +8,6 @@ from odoo.exceptions import UserError, ValidationError from odoo.addons import decimal_precision as dp -from odoo.tools import pycompat - class Pricelist(models.Model): _name = "product.pricelist" @@ -262,7 +260,7 @@ class Pricelist(models.Model): return { product_id: res_tuple[0] for product_id, res_tuple in self._compute_price_rule( - list(pycompat.izip(products, quantities, partners)), + list(zip(products, quantities, partners)), date=date, uom_id=uom_id ).items() @@ -304,7 +302,7 @@ class Pricelist(models.Model): def _price_get_multi(self, pricelist, products_by_qty_by_partner): """ Mono pricelist, multi product - return price per product """ return pricelist.get_products_price( - list(pycompat.izip(**products_by_qty_by_partner))) + list(zip(**products_by_qty_by_partner))) def _get_partner_pricelist(self, partner_id, company_id=None): """ Retrieve the applicable pricelist for a given partner in a given company. diff --git a/addons/product/models/product_template.py b/addons/product/models/product_template.py index c9b6a753a68..866bc898286 100644 --- a/addons/product/models/product_template.py +++ b/addons/product/models/product_template.py @@ -9,7 +9,6 @@ from odoo.addons import decimal_precision as dp from odoo import api, fields, models, tools, _ from odoo.exceptions import ValidationError, RedirectWarning, except_orm -from odoo.tools import pycompat from odoo.exceptions import UserError @@ -182,11 +181,11 @@ class ProductTemplate(models.Model): quantity = self._context.get('quantity', 1.0) # Support context pricelists specified as display_name or ID for compatibility - if isinstance(pricelist_id_or_name, pycompat.string_types): + if isinstance(pricelist_id_or_name, str): pricelist_data = self.env['product.pricelist'].name_search(pricelist_id_or_name, operator='=', limit=1) if pricelist_data: pricelist = self.env['product.pricelist'].browse(pricelist_data[0][0]) - elif isinstance(pricelist_id_or_name, pycompat.integer_types): + elif isinstance(pricelist_id_or_name, int): pricelist = self.env['product.pricelist'].browse(pricelist_id_or_name) if pricelist: @@ -340,7 +339,7 @@ class ProductTemplate(models.Model): templates.with_context(create_from_tmpl=True).create_variant_ids() # This is needed to set given values to first variant after creation - for template, vals in pycompat.izip(templates, vals_list): + for template, vals in zip(templates, vals_list): related_vals = {} if vals.get('barcode'): related_vals['barcode'] = vals['barcode'] diff --git a/addons/sale/tests/test_sale_to_invoice.py b/addons/sale/tests/test_sale_to_invoice.py index 5a66e4c6359..2d6de021ea5 100644 --- a/addons/sale/tests/test_sale_to_invoice.py +++ b/addons/sale/tests/test_sale_to_invoice.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.tools import pycompat, float_is_zero +from odoo.tools import float_is_zero from .test_sale_common import TestCommonSaleNoChart @@ -138,7 +138,7 @@ class TestSaleToInvoice(TestCommonSaleNoChart): invoice.action_invoice_open() # Check discount appeared on both SO lines and invoice lines - for line, inv_line in pycompat.izip(self.sale_order.order_line, invoice.invoice_line_ids): + for line, inv_line in zip(self.sale_order.order_line, invoice.invoice_line_ids): self.assertEquals(line.discount, inv_line.discount, 'Discount on lines of order and invoice should be same') def test_invoice_refund(self): diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py index ed3f845883b..1065250df49 100644 --- a/addons/stock/models/product.py +++ b/addons/stock/models/product.py @@ -4,7 +4,6 @@ from odoo import api, fields, models, _ from odoo.addons import decimal_precision as dp from odoo.exceptions import UserError -from odoo.tools import pycompat from odoo.tools.float_utils import float_round from datetime import datetime import operator as py_operator @@ -167,9 +166,9 @@ class Product(models.Model): ]) location_ids = [] if self.env.context.get('location', False): - if isinstance(self.env.context['location'], pycompat.integer_types): + if isinstance(self.env.context['location'], int): location_ids = [self.env.context['location']] - elif isinstance(self.env.context['location'], pycompat.string_types): + elif isinstance(self.env.context['location'], str): domain = [('complete_name', 'ilike', self.env.context['location'])] if self.env.context.get('force_company', False): domain += [('company_id', '=', self.env.context['force_company'])] @@ -178,9 +177,9 @@ class Product(models.Model): location_ids = self.env.context['location'] else: if self.env.context.get('warehouse', False): - if isinstance(self.env.context['warehouse'], pycompat.integer_types): + if isinstance(self.env.context['warehouse'], int): wids = [self.env.context['warehouse']] - elif isinstance(self.env.context['warehouse'], pycompat.string_types): + elif isinstance(self.env.context['warehouse'], str): domain = [('name', 'ilike', self.env.context['warehouse'])] if self.env.context.get('force_company', False): domain += [('company_id', '=', self.env.context['force_company'])] @@ -316,7 +315,7 @@ class Product(models.Model): @api.model def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): res = super(Product, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu) - if self._context.get('location') and isinstance(self._context['location'], pycompat.integer_types): + if self._context.get('location') and isinstance(self._context['location'], int): location = self.env['stock.location'].browse(self._context['location']) fields = res.get('fields') if fields: diff --git a/addons/stock/models/stock_move_line.py b/addons/stock/models/stock_move_line.py index 5d3c03ed833..b92954e3199 100644 --- a/addons/stock/models/stock_move_line.py +++ b/addons/stock/models/stock_move_line.py @@ -6,7 +6,6 @@ from collections import Counter from odoo import api, fields, models, _ from odoo.addons import decimal_precision as dp from odoo.exceptions import UserError, ValidationError -from odoo.tools.pycompat import izip from odoo.tools.float_utils import float_round, float_compare, float_is_zero diff --git a/addons/stock_account/models/product.py b/addons/stock_account/models/product.py index 81fa093ccd5..c95a3b3cd1f 100644 --- a/addons/stock_account/models/product.py +++ b/addons/stock_account/models/product.py @@ -3,7 +3,7 @@ from odoo import api, fields, models, tools, _ from odoo.exceptions import UserError -from odoo.tools import float_is_zero, pycompat +from odoo.tools import float_is_zero from odoo.addons import decimal_precision as dp from odoo.exceptions import ValidationError diff --git a/addons/stock_account/models/stock.py b/addons/stock_account/models/stock.py index 5a7920108c6..37c69251c19 100644 --- a/addons/stock_account/models/stock.py +++ b/addons/stock_account/models/stock.py @@ -5,7 +5,7 @@ from collections import defaultdict from odoo import api, fields, models, _ from odoo.exceptions import UserError -from odoo.tools import float_compare, float_round, float_is_zero, pycompat +from odoo.tools import float_compare, float_round, float_is_zero import logging _logger = logging.getLogger(__name__) diff --git a/addons/survey/wizard/survey_invite.py b/addons/survey/wizard/survey_invite.py index 4f8f57276cb..7aa47259262 100644 --- a/addons/survey/wizard/survey_invite.py +++ b/addons/survey/wizard/survey_invite.py @@ -10,7 +10,6 @@ from werkzeug import urls from odoo import api, fields, models, _ from odoo.exceptions import UserError -from odoo.tools import pycompat _logger = logging.getLogger(__name__) @@ -215,7 +214,7 @@ class SurveyInvite(models.TransientModel): if wizard.public != 'email_private': return None else: - token = pycompat.text_type(uuid.uuid4()) + token = str(uuid.uuid4()) # create response with token survey_user_input = SurveyUserInput.create({ 'survey_id': wizard.survey_id.id, diff --git a/addons/utm/models/utm_mixin.py b/addons/utm/models/utm_mixin.py index c239501c972..6d9413c51d9 100644 --- a/addons/utm/models/utm_mixin.py +++ b/addons/utm/models/utm_mixin.py @@ -3,7 +3,6 @@ from odoo import api, fields, models, SUPERUSER_ID from odoo.http import request -from odoo.tools import pycompat class UtmMixin(models.AbstractModel): @@ -34,7 +33,7 @@ class UtmMixin(models.AbstractModel): # ir_http dispatch saves the url params in a cookie value = request.httprequest.cookies.get(cookie_name) # if we receive a string for a many2one, we search/create the id - if field.type == 'many2one' and isinstance(value, pycompat.string_types) and value: + if field.type == 'many2one' and isinstance(value, str) and value: Model = self.env[field.comodel_name] records = Model.search([('name', '=', value)], limit=1) if not records: diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 619db9e1403..d0059a25a95 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1490,7 +1490,7 @@ class CSVExport(ExportFormat, http.Controller): row = [] for d in data: # Spreadsheet apps tend to detect formulas on leading =, + and - - if isinstance(d, pycompat.string_types) and d.startswith(('=', '-', '+')): + if isinstance(d, str) and d.startswith(('=', '-', '+')): d = "'" + d row.append(pycompat.to_text(d)) @@ -1533,7 +1533,7 @@ class ExcelExport(ExportFormat, http.Controller): for cell_index, cell_value in enumerate(row): cell_style = base_style - if isinstance(cell_value, bytes) and not isinstance(cell_value, pycompat.string_types): + if isinstance(cell_value, bytes) and not isinstance(cell_value, str): # because xls uses raw export, we can get a bytes object # here. xlwt does not support bytes values in Python 3 -> # assume this is base64 and decode to a string, if this @@ -1543,7 +1543,7 @@ class ExcelExport(ExportFormat, http.Controller): except UnicodeDecodeError: raise UserError(_("Binary fields can not be exported to Excel unless their content is base64-encoded. That does not seem to be the case for %s.") % fields[cell_index]) - if isinstance(cell_value, pycompat.string_types): + if isinstance(cell_value, str): cell_value = re.sub("\r", " ", pycompat.to_text(cell_value)) # Excel supports a maximum of 32767 characters in each cell: cell_value = cell_value[:32767] diff --git a/addons/web/models/ir_qweb.py b/addons/web/models/ir_qweb.py index 058ceb5d87b..ed5441e37ff 100644 --- a/addons/web/models/ir_qweb.py +++ b/addons/web/models/ir_qweb.py @@ -32,7 +32,7 @@ class Image(models.AbstractModel): aclasses = ['img', 'img-fluid'] if options.get('qweb_img_responsive', True) else ['img'] aclasses += options.get('class', '').split() - classes = ' '.join(pycompat.imap(escape, aclasses)) + classes = ' '.join(map(escape, aclasses)) max_size = None if options.get('resize'): diff --git a/addons/web/models/models.py b/addons/web/models/models.py index 2e3bd54788d..fe01ffe6938 100644 --- a/addons/web/models/models.py +++ b/addons/web/models/models.py @@ -3,7 +3,6 @@ from datetime import datetime import babel.dates import pytz -from odoo.tools import pycompat from odoo.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT from odoo import _, api, fields, models diff --git a/addons/web_editor/controllers/main.py b/addons/web_editor/controllers/main.py index 3b1f3cc8ac1..3a2e0d1d7aa 100644 --- a/addons/web_editor/controllers/main.py +++ b/addons/web_editor/controllers/main.py @@ -14,7 +14,6 @@ from lxml import etree, html from odoo.http import request from odoo import http, tools -from odoo.tools import pycompat from odoo.modules.module import get_resource_path, get_module_path logger = logging.getLogger(__name__) @@ -40,7 +39,7 @@ class Web_Editor(http.Controller): debug=request.debug) for k in kwargs: - if isinstance(kwargs[k], pycompat.string_types) and kwargs[k].isdigit(): + if isinstance(kwargs[k], str) and kwargs[k].isdigit(): kwargs[k] = int(kwargs[k]) trans = dict( @@ -205,7 +204,7 @@ class Web_Editor(http.Controller): uploads += attachments.read(['name', 'mimetype', 'checksum', 'url', 'res_id', 'res_model', 'access_token']) except Exception as e: logger.exception("Failed to upload image to attachment") - message = pycompat.text_type(e) + message = str(e) return """<script type='text/javascript'> window.attachments = %s; diff --git a/addons/web_editor/models/ir_qweb.py b/addons/web_editor/models/ir_qweb.py index 22a923e1854..5d006ea1ca9 100644 --- a/addons/web_editor/models/ir_qweb.py +++ b/addons/web_editor/models/ir_qweb.py @@ -223,7 +223,7 @@ class DateTime(models.AbstractModel): attrs = super(DateTime, self).attributes(record, field_name, options, values) if options.get('inherit_branding'): value = record[field_name] - if isinstance(value, pycompat.string_types): + if isinstance(value, str): value = fields.Datetime.from_string(value) if value: # convert from UTC (server timezone) to user timezone diff --git a/addons/web_editor/models/ir_ui_view.py b/addons/web_editor/models/ir_ui_view.py index 532e3de70d9..23bf488ed47 100644 --- a/addons/web_editor/models/ir_ui_view.py +++ b/addons/web_editor/models/ir_ui_view.py @@ -7,7 +7,6 @@ from lxml import etree, html from odoo.exceptions import AccessError from odoo import api, fields, models -from odoo.tools import pycompat _logger = logging.getLogger(__name__) @@ -117,7 +116,7 @@ class IrUiView(models.Model): return False if len(arch1) != len(arch2): return False - return all(self._are_archs_equal(arch1, arch2) for arch1, arch2 in pycompat.izip(arch1, arch2)) + return all(self._are_archs_equal(arch1, arch2) for arch1, arch2 in zip(arch1, arch2)) @api.multi def replace_arch_section(self, section_xpath, replacement, replace_tail=False): @@ -201,9 +200,9 @@ class IrUiView(models.Model): @api.model def _view_obj(self, view_id): - if isinstance(view_id, pycompat.string_types): + if isinstance(view_id, str): return self.search([('key', '=', view_id)]) or self.env.ref(view_id) - elif isinstance(view_id, pycompat.integer_types): + elif isinstance(view_id, int): return self.browse(view_id) # assume it's already a view object (WTF?) return view_id diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py index e68d208fb52..50f1373665a 100644 --- a/addons/website/controllers/main.py +++ b/addons/website/controllers/main.py @@ -16,7 +16,7 @@ import odoo from odoo import http, models, fields, _ from odoo.http import request -from odoo.tools import pycompat, OrderedSet +from odoo.tools import OrderedSet from odoo.addons.http_routing.models.ir_http import slug, _guess_mimetype from odoo.addons.web.controllers.main import Binary from odoo.addons.portal.controllers.portal import pager as portal_pager @@ -410,7 +410,7 @@ class Website(Home): action = action_id = None # find the action_id: either an xml_id, the path, or an ID - if isinstance(path_or_xml_id_or_id, pycompat.string_types) and '.' in path_or_xml_id_or_id: + if isinstance(path_or_xml_id_or_id, str) and '.' in path_or_xml_id_or_id: action = request.env.ref(path_or_xml_id_or_id, raise_if_not_found=False) if not action: action = ServerActions.search([('website_path', '=', path_or_xml_id_or_id), ('website_published', '=', True)], limit=1) diff --git a/addons/website/models/ir_ui_view.py b/addons/website/models/ir_ui_view.py index b739c32c934..f45f602fa8b 100644 --- a/addons/website/models/ir_ui_view.py +++ b/addons/website/models/ir_ui_view.py @@ -10,7 +10,6 @@ from odoo import tools from odoo.addons.http_routing.models.ir_http import url_for from odoo.osv import expression from odoo.http import request -from odoo.tools import pycompat _logger = logging.getLogger(__name__) @@ -167,7 +166,7 @@ class View(models.Model): @api.model def _view_obj(self, view_id): - if isinstance(view_id, pycompat.string_types): + if isinstance(view_id, str): if 'website_id' in self._context: domain = [('key', '=', view_id)] + self.env['website'].website_domain(self._context.get('website_id')) order = 'website_id' @@ -179,7 +178,7 @@ class View(models.Model): return views.filter_duplicate() else: return self.env.ref(view_id) - elif isinstance(view_id, pycompat.integer_types): + elif isinstance(view_id, int): return self.browse(view_id) # assume it's already a view object (WTF?) @@ -216,7 +215,7 @@ class View(models.Model): @api.model @tools.ormcache_context('self._uid', 'xml_id', keys=('website_id',)) def get_view_id(self, xml_id): - if 'website_id' in self._context and not isinstance(xml_id, pycompat.integer_types): + if 'website_id' in self._context and not isinstance(xml_id, int): current_website = self.env['website'].browse(self._context.get('website_id')) domain = ['&', ('key', '=', xml_id)] + current_website.website_domain() diff --git a/addons/website/models/res_partner.py b/addons/website/models/res_partner.py index 81ae2e73b92..45d65919cd9 100644 --- a/addons/website/models/res_partner.py +++ b/addons/website/models/res_partner.py @@ -4,7 +4,6 @@ import werkzeug from odoo import api, fields, models -from odoo.tools.pycompat import izip def urlplus(url, params): @@ -51,5 +50,5 @@ class Partner(models.Model): super(Partner, self2)._compute_display_name() # onchange uses the cache to retrieve value, we need to copy computed_value into the initial env - for record, record2 in izip(self, self2): + for record, record2 in zip(self, self2): record.display_name = record2.display_name diff --git a/addons/website/models/website.py b/addons/website/models/website.py index 66b73c95b37..593c1b721d7 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -13,7 +13,6 @@ from odoo import api, fields, models, tools from odoo.addons.http_routing.models.ir_http import slugify, _guess_mimetype from odoo.addons.website.models.ir_http import sitemap_qs2dom from odoo.addons.portal.controllers.portal import pager -from odoo.tools import pycompat from odoo.http import request from odoo.osv import expression from odoo.osv.expression import FALSE_DOMAIN @@ -509,7 +508,7 @@ class Website(models.Model): @api.model def get_template(self, template): View = self.env['ir.ui.view'] - if isinstance(template, pycompat.integer_types): + if isinstance(template, int): view_id = template else: if '.' not in template: @@ -1187,7 +1186,7 @@ class Menu(models.Model): for menu in data['data']: mid = menu['id'] # new menu are prefixed by new- - if isinstance(mid, pycompat.string_types): + if isinstance(mid, str): new_menu = self.create({'name': menu['name'], 'website_id': website_id}) replace_id(mid, new_menu.id) for menu in data['data']: diff --git a/addons/website/tests/test_crawl.py b/addons/website/tests/test_crawl.py index 2c138658740..81907aa3a16 100644 --- a/addons/website/tests/test_crawl.py +++ b/addons/website/tests/test_crawl.py @@ -10,7 +10,6 @@ from werkzeug import urls import odoo import re -from odoo.tools import pycompat _logger = logging.getLogger(__name__) diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py index 960a241d948..ab1c3d97288 100644 --- a/addons/website_forum/models/forum.py +++ b/addons/website_forum/models/forum.py @@ -12,7 +12,7 @@ from werkzeug.exceptions import Forbidden from odoo import api, fields, models, modules, tools, SUPERUSER_ID, _ from odoo.exceptions import UserError, ValidationError -from odoo.tools import pycompat, misc +from odoo.tools import misc _logger = logging.getLogger(__name__) @@ -376,7 +376,7 @@ class Post(models.Model): is_admin = user.id == SUPERUSER_ID # sudoed recordset instead of individual posts so values can be # prefetched in bulk - for post, post_sudo in pycompat.izip(self, self.sudo()): + for post, post_sudo in zip(self, self.sudo()): is_creator = post.create_uid == user post.karma_accept = post.forum_id.karma_answer_accept_own if post.parent_id.create_uid == user else post.forum_id.karma_answer_accept_all diff --git a/addons/website_sale/models/product.py b/addons/website_sale/models/product.py index d1ddf51c581..d8921442080 100644 --- a/addons/website_sale/models/product.py +++ b/addons/website_sale/models/product.py @@ -3,7 +3,6 @@ from odoo import api, fields, models, tools, _ from odoo.addons import decimal_precision as dp -from odoo.tools import pycompat from odoo.tools.translate import html_translate from odoo.tools import float_is_zero @@ -137,7 +136,7 @@ class ProductTemplate(models.Model): # This makes sure that every template below has a corresponding product in the zipped result. self = self.filtered('product_variant_id') # use mapped who returns a recordset with only itself to prefetch (and don't prefetch every product_variant_ids) - for template, product in pycompat.izip(self, self.mapped('product_variant_id')): + for template, product in zip(self, self.mapped('product_variant_id')): template.website_price = product.website_price template.website_public_price = product.website_public_price template.website_price_difference = product.website_price_difference @@ -204,7 +203,7 @@ class Product(models.Model): ret = self.env.user.has_group('account.group_show_line_subtotals_tax_excluded') and 'total_excluded' or 'total_included' - for p, p2 in pycompat.izip(self, self2): + for p, p2 in zip(self, self2): taxes = partner.property_account_position_id.map_tax(p.sudo().taxes_id.filtered(lambda x: x.company_id == company_id), p, partner) p.website_price = taxes.compute_all(p2.price, pricelist.currency_id, quantity=qty, product=p2, partner=partner)[ret] price_without_pricelist = taxes.compute_all(p.list_price, pricelist.currency_id)[ret] diff --git a/doc/_extensions/github_link.py b/doc/_extensions/github_link.py index 72d51bfeb60..8f7a0084039 100644 --- a/doc/_extensions/github_link.py +++ b/doc/_extensions/github_link.py @@ -4,8 +4,6 @@ import os.path from werkzeug import urls -from odoo.tools import pycompat - """ * adds github_link(mode) context variable: provides URL (in relevant mode) of current document on github @@ -100,7 +98,7 @@ def add_doc_link(app, pagename, templatename, context, doctree): # in 1.3 source_suffix can be a list # in 1.8 source_suffix can be a mapping # FIXME: will break if we ever add support for !rst markdown documents maybe - if not isinstance(source_suffix, pycompat.string_types): + if not isinstance(source_suffix, str): source_suffix = next(iter(source_suffix)) # can't use functools.partial because 3rd positional is line not mode context['github_link'] = lambda mode='edit': make_github_link( diff --git a/doc/_extensions/odoo_ext/translator.py b/doc/_extensions/odoo_ext/translator.py index 491f02a2ad3..211159e219c 100644 --- a/doc/_extensions/odoo_ext/translator.py +++ b/doc/_extensions/odoo_ext/translator.py @@ -13,8 +13,6 @@ from docutils import nodes from sphinx import addnodes, util from sphinx.locale import admonitionlabels -from odoo.tools import pycompat - def _parents(node): while node.parent: @@ -66,7 +64,7 @@ class BootstrapTranslator(nodes.NodeVisitor, object): self.param_separator = ',' def encode(self, text): - return pycompat.text_type(text).translate({ + return str(text).translate({ ord('&'): u'&', ord('<'): u'<', ord('"'): u'"', @@ -75,7 +73,7 @@ class BootstrapTranslator(nodes.NodeVisitor, object): }) def starttag(self, node, tagname, **attributes): - tagname = pycompat.text_type(tagname).lower() + tagname = str(tagname).lower() # extract generic attributes attrs = {name.lower(): value for name, value in attributes.items()} @@ -110,7 +108,7 @@ class BootstrapTranslator(nodes.NodeVisitor, object): # only "space characters" SPACE, CHARACTER TABULATION, LINE FEED, # FORM FEED and CARRIAGE RETURN should be collapsed, not al White_Space def attval(self, value, whitespace=re.compile(u'[ \t\n\f\r]+')): - return self.encode(whitespace.sub(u' ', pycompat.text_type(value))) + return self.encode(whitespace.sub(' ', str(value))) def astext(self): return u''.join(self.body) diff --git a/doc/python3.rst b/doc/python3.rst index 88475d7dc4a..ac24983ceb7 100644 --- a/doc/python3.rst +++ b/doc/python3.rst @@ -299,8 +299,6 @@ under the single ``int`` type. * the ``L`` suffix for integer literals must be removed * calls to ``long`` must be replaced by calls to ``int`` - * ``(int, long)`` for type-checking purposes must be replaced by - :py:data:`odoo.tools.pycompat.integer_types` * the ``L`` suffix on numbers is unsupported in Python 3, and unnecessary in @@ -311,18 +309,6 @@ under the single ``int`` type. subtype of ``int`` (nor the reverse), and ``isinstance(value, (int, long))`` is thus generally necessary to catch all integrals. - For that case, Odoo 11 now provides a compatibility module with an - :py:data:`~odoo.tools.pycompat.integer_types` definition which can be used - for type-testing. - - It is a tuple of types so when used with ``isinstance`` it can be provided - directly or inside an other tuple alongside other types e.g. - ``isinstance(value, (BaseModel, integer_types))``. - - However when used with ``type`` directly (which should be avoided) you - should use the ``in`` operator, and if you need other types you need to - concatenate ``integer_types`` to an other tuple. - ``reduce`` ########## @@ -411,18 +397,6 @@ Both versions have the following prefixes for string literals: For best cross-version compatibility you should avoid unprefixed string literals unless you *specifically* need a "native string" [#native-string]_. -For easier type-testing, :mod:`odoo.tools.pycompat` provides the following -constants: - -* :data:`~odoo.tools.pycompat.string_types` is an alias/type tuple for testing - string types, essentially a replacement of testing for ``basestring`` or - ``(str, unicode)``. -* :data:`~odoo.tools.pycompat.text_type` is the proper *text* type for the - current version, it should mostly be used for converting non-bytes objects - to text. -* ``bytes`` should be avoided for type conversions, though it can be used to - check if an object is a bytestring. - ``open`` -------- diff --git a/odoo/addons/base/models/assetsbundle.py b/odoo/addons/base/models/assetsbundle.py index f3754859b4b..73a569b5bd8 100644 --- a/odoo/addons/base/models/assetsbundle.py +++ b/odoo/addons/base/models/assetsbundle.py @@ -17,7 +17,7 @@ from datetime import datetime from subprocess import Popen, PIPE from collections import OrderedDict from odoo import fields, tools, SUPERUSER_ID -from odoo.tools.pycompat import string_types, to_text +from odoo.tools.pycompat import to_text from odoo.http import request from odoo.modules.module import get_resource_path from .qweb import escape @@ -120,7 +120,7 @@ class AssetsBundle(object): for tagName, attributes, content in nodes: html = u"<%s " % tagName for name, value in attributes.items(): - if value or isinstance(value, string_types): + if value or isinstance(value, str): html += u' %s="%s"' % (name, escape(to_text(value))) if content is None: html += u'/>' @@ -602,7 +602,7 @@ class WebAsset(object): tagName, attributes, content = self.to_node() html = u"<%s " % tagName for name, value in attributes.items(): - if value or isinstance(value, string_types): + if value or isinstance(value, str): html += u' %s="%s"' % (name, escape(to_text(value))) if content is None: html += u'/>' diff --git a/odoo/addons/base/models/ir_actions.py b/odoo/addons/base/models/ir_actions.py index 634e5f60ca8..bb45ea1a75f 100644 --- a/odoo/addons/base/models/ir_actions.py +++ b/odoo/addons/base/models/ir_actions.py @@ -5,7 +5,7 @@ import odoo from odoo import api, fields, models, tools, SUPERUSER_ID, _ from odoo.exceptions import MissingError, UserError, ValidationError, AccessError from odoo.tools.safe_eval import safe_eval, test_python_expr -from odoo.tools import pycompat, wrap_module +from odoo.tools import wrap_module from odoo.http import request import base64 @@ -774,7 +774,7 @@ class IrActionsActClient(models.Model): @api.depends('params_store') def _compute_params(self): self_bin = self.with_context(bin_size=False, bin_size_params_store=False) - for record, record_bin in pycompat.izip(self, self_bin): + for record, record_bin in zip(self, self_bin): record.params = record_bin.params_store and safe_eval(record_bin.params_store, {'uid': self._uid}) def _inverse_params(self): diff --git a/odoo/addons/base/models/ir_config_parameter.py b/odoo/addons/base/models/ir_config_parameter.py index eed10daadd8..04f8062d1f1 100644 --- a/odoo/addons/base/models/ir_config_parameter.py +++ b/odoo/addons/base/models/ir_config_parameter.py @@ -8,7 +8,7 @@ import uuid import logging from odoo import api, fields, models -from odoo.tools import config, ormcache, mute_logger, pycompat +from odoo.tools import config, ormcache, mute_logger _logger = logging.getLogger(__name__) @@ -16,8 +16,8 @@ _logger = logging.getLogger(__name__) A dictionary holding some configuration parameters to be initialized when the database is created. """ _default_parameters = { - "database.secret": lambda: pycompat.text_type(uuid.uuid4()), - "database.uuid": lambda: pycompat.text_type(uuid.uuid1()), + "database.secret": lambda: str(uuid.uuid4()), + "database.uuid": lambda: str(uuid.uuid1()), "database.create_date": fields.Datetime.now, "web.base.url": lambda: "http://localhost:%s" % config.get('http_port'), "base.login_cooldown_after": lambda: 10, diff --git a/odoo/addons/base/models/ir_fields.py b/odoo/addons/base/models/ir_fields.py index 90208e7a86a..e6392441f74 100644 --- a/odoo/addons/base/models/ir_fields.py +++ b/odoo/addons/base/models/ir_fields.py @@ -8,7 +8,7 @@ import psycopg2 import pytz from odoo import api, fields, models, _ -from odoo.tools import ustr, pycompat +from odoo.tools import ustr REFERENCING_FIELDS = {None, 'id', '.id'} def only_ref_fields(record): @@ -39,9 +39,9 @@ class IrFieldsConverter(models.AbstractModel): @api.model def _format_import_error(self, error_type, error_msg, error_params=(), error_args=None): # sanitize error params for later formatting by the import system - sanitize = lambda p: p.replace('%', '%%') if isinstance(p, pycompat.string_types) else p + sanitize = lambda p: p.replace('%', '%%') if isinstance(p, str) else p if error_params: - if isinstance(error_params, pycompat.string_types): + if isinstance(error_params, str): error_params = sanitize(error_params) elif isinstance(error_params, dict): error_params = {k: sanitize(v) for k, v in error_params.items()} @@ -79,7 +79,7 @@ class IrFieldsConverter(models.AbstractModel): try: converted[field], ws = converters[field](value) for w in ws: - if isinstance(w, pycompat.string_types): + if isinstance(w, str): # wrap warning string in an ImportWarning for # uniform handling w = ImportWarning(w) @@ -270,14 +270,14 @@ class IrFieldsConverter(models.AbstractModel): for item, label in selection: label = ustr(label) labels = [label] + self._get_translations(('selection', 'model', 'code'), label) - if value == pycompat.text_type(item) or value in labels: + if value == str(item) or value in labels: return item, [] raise self._format_import_error( ValueError, _(u"Value '%s' not found in selection field '%%(field)s'"), value, - {'moreinfo': [_label or pycompat.text_type(item) for item, _label in selection if _label or item]} + {'moreinfo': [_label or str(item) for item, _label in selection if _label or item]} ) @api.model diff --git a/odoo/addons/base/models/ir_http.py b/odoo/addons/base/models/ir_http.py index 205be37929e..63d12137d7a 100644 --- a/odoo/addons/base/models/ir_http.py +++ b/odoo/addons/base/models/ir_http.py @@ -332,7 +332,7 @@ class IrHttp(models.AbstractModel): if module_resource_path.startswith(module_path): with open(module_resource_path, 'rb') as f: content = base64.b64encode(f.read()) - last_update = pycompat.text_type(os.path.getmtime(module_resource_path)) + last_update = str(os.path.getmtime(module_resource_path)) if not module_resource_path: module_resource_path = obj.url diff --git a/odoo/addons/base/models/ir_mail_server.py b/odoo/addons/base/models/ir_mail_server.py index 3bc39f4cb54..b7597ebaa77 100644 --- a/odoo/addons/base/models/ir_mail_server.py +++ b/odoo/addons/base/models/ir_mail_server.py @@ -62,7 +62,7 @@ def encode_header(header_text): return "" header_text = ustr(header_text) # FIXME: require unicode higher up? if is_ascii(header_text): - return pycompat.to_native(header_text) + return pycompat.to_text(header_text) return Header(header_text, 'utf-8') def encode_header_param(param_text): @@ -83,7 +83,7 @@ def encode_header_param(param_text): return "" param_text = ustr(param_text) # FIXME: require unicode higher up? if is_ascii(param_text): - return pycompat.to_native(param_text) # TODO: is that actually necessary? + return pycompat.to_text(param_text) # TODO: is that actually necessary? return Charset("utf-8").header_encode(param_text) address_pattern = re.compile(r'([^ ,<@]+@[^> ,]+)') @@ -121,7 +121,7 @@ def encode_rfc2822_address_header(header_text): name = Header(pycompat.to_text(name)).encode() return formataddr((name, email)) - addresses = getaddresses([pycompat.to_native(ustr(header_text))]) + addresses = getaddresses([pycompat.to_text(ustr(header_text))]) return COMMASPACE.join(encode_addr(a) for a in addresses) @@ -268,8 +268,8 @@ class IrMailServer(models.Model): # The user/password must be converted to bytestrings in order to be usable for # certain hashing schemes, like HMAC. # See also bug #597143 and python issue #5285 - smtp_user = pycompat.to_native(ustr(smtp_user)) - smtp_password = pycompat.to_native(ustr(smtp_password)) + smtp_user = pycompat.to_text(ustr(smtp_user)) + smtp_password = pycompat.to_text(ustr(smtp_password)) connection.login(smtp_user, smtp_password) return connection @@ -344,7 +344,7 @@ class IrMailServer(models.Model): msg['Date'] = formatdate() # Custom headers may override normal headers or provide additional ones for key, value in headers.items(): - msg[pycompat.to_native(ustr(key))] = encode_header(value) + msg[pycompat.to_text(ustr(key))] = encode_header(value) if subtype == 'html' and not body_alternative: # Always provide alternative text body ourselves if possible. diff --git a/odoo/addons/base/models/ir_model.py b/odoo/addons/base/models/ir_model.py index c9b45104c65..089689a35a2 100644 --- a/odoo/addons/base/models/ir_model.py +++ b/odoo/addons/base/models/ir_model.py @@ -282,7 +282,7 @@ class IrModel(models.Model): def _instanciate(self, model_data): """ Return a class for the custom model given by parameters ``model_data``. """ class CustomModel(models.Model): - _name = pycompat.to_native(model_data['model']) + _name = pycompat.to_text(model_data['model']) _description = model_data['name'] _module = False _custom = True @@ -1152,7 +1152,7 @@ class IrModelAccess(models.Model): else: model_name = model - if isinstance(group_ids, pycompat.integer_types): + if isinstance(group_ids, int): group_ids = [group_ids] query = """ SELECT 1 FROM ir_model_access a @@ -1190,7 +1190,7 @@ class IrModelAccess(models.Model): # User root have all accesses return True - assert isinstance(model, pycompat.string_types), 'Not a model name: %s' % (model,) + assert isinstance(model, str), 'Not a model name: %s' % (model,) assert mode in ('read', 'write', 'create', 'unlink'), 'Invalid access mode' # TransientModel records have no access rights, only an implicit access rule diff --git a/odoo/addons/base/models/ir_module.py b/odoo/addons/base/models/ir_module.py index 350b4d7a489..824365424cc 100644 --- a/odoo/addons/base/models/ir_module.py +++ b/odoo/addons/base/models/ir_module.py @@ -14,8 +14,6 @@ import zipfile import requests -from odoo.tools import pycompat - from docutils import nodes from docutils.core import publish_string from docutils.transforms import Transform, writer_aux @@ -684,7 +682,7 @@ class Module(models.Model): updated_values = {} for key in values: old = getattr(mod, key) - updated = tools.ustr(values[key]) if isinstance(values[key], pycompat.string_types) else values[key] + updated = tools.ustr(values[key]) if isinstance(values[key], str) else values[key] if (old or updated) and updated != old: updated_values[key] = values[key] if terp.get('installable', True) and mod.state == 'uninstallable': diff --git a/odoo/addons/base/models/ir_property.py b/odoo/addons/base/models/ir_property.py index cfe3cd968d7..2d5c1742cfa 100644 --- a/odoo/addons/base/models/ir_property.py +++ b/odoo/addons/base/models/ir_property.py @@ -3,7 +3,7 @@ from odoo import api, fields, models, _ from odoo.exceptions import UserError -from odoo.tools import pycompat, ormcache +from odoo.tools import ormcache TYPE2FIELD = { 'char': 'value_text', @@ -82,7 +82,7 @@ class Property(models.Model): if field == 'value_reference': if isinstance(value, models.BaseModel): value = '%s,%d' % (value._name, value.id) - elif isinstance(value, pycompat.integer_types): + elif isinstance(value, int): field_id = values.get('fields_id') if not field_id: if not prop: diff --git a/odoo/addons/base/models/ir_qweb.py b/odoo/addons/base/models/ir_qweb.py index 18717316f57..2e4070d2665 100644 --- a/odoo/addons/base/models/ir_qweb.py +++ b/odoo/addons/base/models/ir_qweb.py @@ -11,8 +11,6 @@ from lxml import html from lxml import etree from werkzeug import urls -from odoo.tools import pycompat - from odoo import api, models, tools from odoo.tools.safe_eval import assert_valid_codeobj, _BUILTINS, _SAFE_OPCODES from odoo.http import request @@ -130,7 +128,7 @@ class IrQWeb(models.AbstractModel, QWeb): view = self.env['ir.ui.view'].browse(view_id) return view.inherit_id is not None - if isinstance(name, pycompat.integer_types) or is_child_view(name): + if isinstance(name, int) or is_child_view(name): for node in etree.fromstring(template): if node.get('t-name'): node.set('t-name', str(name)) diff --git a/odoo/addons/base/models/ir_qweb_fields.py b/odoo/addons/base/models/ir_qweb_fields.py index 023a9b6ef07..81e4c700d1a 100644 --- a/odoo/addons/base/models/ir_qweb_fields.py +++ b/odoo/addons/base/models/ir_qweb_fields.py @@ -234,7 +234,7 @@ class DateTimeConverter(models.AbstractModel): lang = self.user_lang() locale = babel.Locale.parse(lang.code) - if isinstance(value, pycompat.string_types): + if isinstance(value, str): value = fields.Datetime.from_string(value) value = fields.Datetime.context_timestamp(self, value) @@ -572,7 +572,7 @@ class RelativeDatetimeConverter(models.AbstractModel): def value_to_html(self, value, options): locale = babel.Locale.parse(self.user_lang().code) - if isinstance(value, pycompat.string_types): + if isinstance(value, str): value = fields.Datetime.from_string(value) # value should be a naive datetime in UTC. So is fields.Datetime.now() diff --git a/odoo/addons/base/models/ir_translation.py b/odoo/addons/base/models/ir_translation.py index 103f5a64675..4aeae7c2cd6 100644 --- a/odoo/addons/base/models/ir_translation.py +++ b/odoo/addons/base/models/ir_translation.py @@ -8,7 +8,6 @@ from difflib import get_close_matches from odoo import api, fields, models, tools, SUPERUSER_ID, _ from odoo.exceptions import AccessError, UserError, ValidationError from odoo.modules import get_module_path, get_module_resource -from odoo.tools import pycompat _logger = logging.getLogger(__name__) @@ -406,10 +405,10 @@ class IrTranslation(models.Model): # always pass unicode so we can remove the string encoding/decoding. if not lang: return tools.ustr(source or '') - if isinstance(types, pycompat.string_types): + if isinstance(types, str): types = (types,) if res_id: - if isinstance(res_id, pycompat.integer_types): + if isinstance(res_id, int): res_id = (res_id,) else: res_id = tuple(res_id) diff --git a/odoo/addons/base/models/ir_ui_view.py b/odoo/addons/base/models/ir_ui_view.py index 2c49ee065b8..b1c2a02505e 100644 --- a/odoo/addons/base/models/ir_ui_view.py +++ b/odoo/addons/base/models/ir_ui_view.py @@ -277,11 +277,11 @@ actual arch. @api.depends('arch') def _compute_arch_base(self): # 'arch_base' is the same as 'arch' without translation - for view, view_wo_lang in pycompat.izip(self, self.with_context(lang=None)): + for view, view_wo_lang in zip(self, self.with_context(lang=None)): view.arch_base = view_wo_lang.arch def _inverse_arch_base(self): - for view, view_wo_lang in pycompat.izip(self, self.with_context(lang=None)): + for view, view_wo_lang in zip(self, self.with_context(lang=None)): view_wo_lang.arch = view.arch_base @api.depends('write_date') @@ -293,7 +293,7 @@ actual arch. view.model_data_id = data['id'] def _search_model_data_id(self, operator, value): - name = 'name' if isinstance(value, pycompat.string_types) else 'id' + name = 'name' if isinstance(value, str) else 'id' domain = [('model', '=', 'ir.ui.view'), (name, operator, value)] data = self.env['ir.model.data'].sudo().search(domain) return [('id', 'in', data.mapped('res_id'))] @@ -1030,7 +1030,7 @@ actual arch. if editable and not node.get('domain'): domain = field._description_domain(self.env) # process the field's domain as if it was in the view - if isinstance(domain, pycompat.string_types): + if isinstance(domain, str): process_expr(domain, get, 'domain', domain) # retrieve subfields of 'parent' model = self.env[field.comodel_name] @@ -1175,7 +1175,7 @@ actual arch. view ID or an XML ID. Note that this method may be overridden for other kinds of template values. """ - if isinstance(template, pycompat.integer_types): + if isinstance(template, int): return template if '.' not in template: raise ValueError('Invalid template id: %r' % template) @@ -1277,7 +1277,7 @@ actual arch. @api.multi def render(self, values=None, engine='ir.qweb', minimal_qcontext=False): - assert isinstance(self.id, pycompat.integer_types) + assert isinstance(self.id, int) qcontext = dict() if minimal_qcontext else self._prepare_qcontext() qcontext.update(values or {}) diff --git a/odoo/addons/base/models/qweb.py b/odoo/addons/base/models/qweb.py index 51693c55cb1..071967093d4 100644 --- a/odoo/addons/base/models/qweb.py +++ b/odoo/addons/base/models/qweb.py @@ -35,18 +35,6 @@ unsafe_eval = eval _logger = logging.getLogger(__name__) -# in Python 2, arguments (within the ast.arguments structure) are expressions -# (since they can be tuples), generally -# ast.Name(id: identifyer, ctx=ast.Param()), whereas in Python 3 they are -# ast.arg(arg: identifier, annotation: expr?) provide a toplevel arg() -# function which matches ast.arg producing the relevant ast.Name in Python 2. -arg = getattr(ast, 'arg', lambda arg, annotation: ast.Name(id=arg, ctx=ast.Param())) -# also Python 3's arguments has grown *2* new mandatory arguments, kwonlyargs -# and kw_defaults for keyword-only arguments and their default values (if any) -# so add a shim for *that* based on the signature of Python 3 I guess? -arguments = ast.arguments -if pycompat.PY2: - arguments = lambda args, vararg, kwonlyargs, kw_defaults, kwarg, defaults: ast.arguments(args=args, vararg=vararg, kwarg=kwarg, defaults=defaults) #################################### ### qweb tools ### #################################### @@ -98,7 +86,7 @@ class Contextifier(ast.NodeTransformer): if args.kwarg: names.append(args.kwarg) # remap defaults in case there's any return ast.copy_location(ast.Lambda( - args=arguments( + args=ast.arguments( args=args.args, defaults=[self.visit(default) for default in args.defaults], vararg=args.vararg, @@ -190,7 +178,7 @@ def foreach_iterator(base_ctx, enum, name): if isinstance(enum, Mapping): enum = enum.items() else: - enum = pycompat.izip(*tee(enum)) + enum = zip(*tee(enum)) value_key = '%s_value' % name index_key = '%s_index' % name first_key = '%s_first' % name @@ -526,11 +514,10 @@ class QWeb(object): Define: * escape * to_text (empty string for a None or False, otherwise unicode string) - * string_types (replacement for basestring) """ return ast.parse(dedent(""" from collections import OrderedDict - from odoo.tools.pycompat import to_text, string_types + from odoo.tools.pycompat import to_text from odoo.addons.base.models.qweb import escape, foreach_iterator """)) @@ -547,12 +534,12 @@ class QWeb(object): # def $name(self, append, values, options, log) fn = ast.FunctionDef( name=name, - args=arguments(args=[ - arg(arg='self', annotation=None), - arg(arg='append', annotation=None), - arg(arg='values', annotation=None), - arg(arg='options', annotation=None), - arg(arg='log', annotation=None), + args=ast.arguments(args=[ + ast.arg(arg='self', annotation=None), + ast.arg(arg='append', annotation=None), + ast.arg(arg='values', annotation=None), + ast.arg(arg='options', annotation=None), + ast.arg(arg='log', annotation=None), ], defaults=[], vararg=None, kwarg=None, kwonlyargs=[], kw_defaults=[]), body=body or [ast.Return()], decorator_list=[]) @@ -743,7 +730,7 @@ class QWeb(object): func=ast.Name(id='isinstance', ctx=ast.Load()), args=[ ast.Name(id='value', ctx=ast.Load()), - ast.Name(id='string_types', ctx=ast.Load()) + ast.Name(id='str', ctx=ast.Load()) ], keywords=[], starargs=None, kwargs=None @@ -1508,7 +1495,7 @@ class QWeb(object): keys = [] values = [] for key, value in options['nsmap'].items(): - if isinstance(key, pycompat.string_types): + if isinstance(key, str): keys.append(ast.Str(s=key)) elif key is None: keys.append(ast.Name(id='None', ctx=ast.Load())) @@ -1646,7 +1633,7 @@ class QWeb(object): for m in _FORMAT_REGEX.finditer(f): literal = f[base_idx:m.start()] if literal: - elts.append(ast.Str(literal if isinstance(literal, pycompat.text_type) else literal.decode('utf-8'))) + elts.append(ast.Str(literal if isinstance(literal, str) else literal.decode('utf-8'))) expr = m.group(1) or m.group(2) elts.append(self._compile_strexpr(expr)) @@ -1654,7 +1641,7 @@ class QWeb(object): # string past last regex match literal = f[base_idx:] if literal: - elts.append(ast.Str(literal if isinstance(literal, pycompat.text_type) else literal.decode('utf-8'))) + elts.append(ast.Str(literal if isinstance(literal, str) else literal.decode('utf-8'))) return reduce(lambda acc, it: ast.BinOp( left=acc, diff --git a/odoo/addons/base/models/res_bank.py b/odoo/addons/base/models/res_bank.py index 88ff7b7984c..0a2392f38e0 100644 --- a/odoo/addons/base/models/res_bank.py +++ b/odoo/addons/base/models/res_bank.py @@ -6,7 +6,6 @@ import collections from odoo import api, fields, models, _ from odoo.osv import expression -from odoo.tools import pycompat import werkzeug.urls @@ -108,7 +107,7 @@ class ResPartnerBank(models.Model): if args[pos][0] == 'acc_number': op = args[pos][1] value = args[pos][2] - if not isinstance(value, pycompat.string_types) and isinstance(value, collections.Iterable): + if not isinstance(value, str) and isinstance(value, collections.Iterable): value = [sanitize_account_number(i) for i in value] else: value = sanitize_account_number(value) diff --git a/odoo/addons/base/models/res_partner.py b/odoo/addons/base/models/res_partner.py index 6792f44b772..522387d2fbb 100644 --- a/odoo/addons/base/models/res_partner.py +++ b/odoo/addons/base/models/res_partner.py @@ -18,7 +18,6 @@ from odoo import api, fields, models, tools, SUPERUSER_ID, _ from odoo.modules import get_module_resource from odoo.osv.expression import get_unaccent_wrapper from odoo.exceptions import UserError, ValidationError -from odoo.tools import pycompat # Global variables used for the warning fields declared on the res.partner # in the following modules : sale, purchase, account, stock @@ -551,7 +550,7 @@ class Partner(models.Model): vals['image'] = self._get_default_image(vals.get('type'), vals.get('is_company'), vals.get('parent_id')) tools.image_resize_images(vals, sizes={'image': (1024, None)}) partners = super(Partner, self).create(vals_list) - for partner, vals in pycompat.izip(partners, vals_list): + for partner, vals in zip(partners, vals_list): partner._fields_sync(vals) partner._handle_first_contact_creation() return partners diff --git a/odoo/addons/base/models/res_users.py b/odoo/addons/base/models/res_users.py index 5b4202da7c2..dfa5f61e25b 100644 --- a/odoo/addons/base/models/res_users.py +++ b/odoo/addons/base/models/res_users.py @@ -21,7 +21,7 @@ from odoo.exceptions import AccessDenied, AccessError, UserError, ValidationErro from odoo.http import request from odoo.osv import expression from odoo.service.db import check_super -from odoo.tools import partition, pycompat, collections +from odoo.tools import partition, collections _logger = logging.getLogger(__name__) @@ -110,7 +110,7 @@ class Groups(models.Model): @api.depends('category_id.name', 'name') def _compute_full_name(self): # Important: value must be stored in environment of group, not group1! - for group, group1 in pycompat.izip(self, self.sudo()): + for group, group1 in zip(self, self.sudo()): if group1.category_id: group.full_name = '%s / %s' % (group1.category_id.name, group1.name) else: @@ -124,7 +124,7 @@ class Groups(models.Model): return expression.AND(domains) else: return expression.OR(domains) - if isinstance(operand, pycompat.string_types): + if isinstance(operand, str): lst = False operand = [operand] where = [] @@ -421,7 +421,7 @@ class Users(models.Model): @api.model def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): - groupby_fields = set([groupby] if isinstance(groupby, pycompat.string_types) else groupby) + groupby_fields = set([groupby] if isinstance(groupby, str) else groupby) if groupby_fields.intersection(USER_PRIVATE_FIELDS): raise AccessError(_("Invalid 'group by' parameter")) return super(Users, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) @@ -910,7 +910,7 @@ class GroupsImplied(models.Model): def create(self, vals_list): user_ids_list = [vals.pop('users', None) for vals in vals_list] groups = super(GroupsImplied, self).create(vals_list) - for group, user_ids in pycompat.izip(groups, user_ids_list): + for group, user_ids in zip(groups, user_ids_list): if user_ids: # delegate addition of users to add implied groups group.write({'users': user_ids}) @@ -922,7 +922,7 @@ class GroupsImplied(models.Model): if values.get('users') or values.get('implied_ids'): # add all implied groups (to all users of each group) for group in self: - vals = {'users': list(pycompat.izip(repeat(4), group.with_context(active_test=False).users.ids))} + vals = {'users': list(zip(repeat(4), group.with_context(active_test=False).users.ids))} super(GroupsImplied, group.trans_implied_ids).write(vals) return res @@ -1164,8 +1164,8 @@ class UsersView(models.Model): if 'groups_id' not in values and (add or rem): # remove group ids in `rem` and add group ids in `add` values1['groups_id'] = list(itertools.chain( - pycompat.izip(repeat(3), rem), - pycompat.izip(repeat(4), add) + zip(repeat(3), rem), + zip(repeat(4), add) )) return values1 diff --git a/odoo/addons/base/tests/test_api.py b/odoo/addons/base/tests/test_api.py index 270a8d75df4..5c7c2ef64d3 100644 --- a/odoo/addons/base/tests/test_api.py +++ b/odoo/addons/base/tests/test_api.py @@ -2,7 +2,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import models -from odoo.tools import mute_logger, pycompat +from odoo.tools import mute_logger from odoo.tests import common from odoo.exceptions import AccessError @@ -69,8 +69,8 @@ class TestAPI(common.TransactionCase): self.cr.execute("SELECT COUNT(*) FROM res_partner WHERE active") count1 = self.cr.fetchone()[0] count2 = self.env['res.partner'].search([], count=True) - self.assertIsInstance(count1, pycompat.integer_types) - self.assertIsInstance(count2, pycompat.integer_types) + self.assertIsInstance(count1, int) + self.assertIsInstance(count2, int) self.assertEqual(count1, count2) @mute_logger('odoo.models') diff --git a/odoo/addons/base/tests/test_float.py b/odoo/addons/base/tests/test_float.py index a5f91982303..4447b9de1c0 100644 --- a/odoo/addons/base/tests/test_float.py +++ b/odoo/addons/base/tests/test_float.py @@ -4,7 +4,7 @@ from math import log10 from odoo.tests.common import TransactionCase -from odoo.tools import float_compare, float_is_zero, float_repr, float_round, float_split_str, pycompat +from odoo.tools import float_compare, float_is_zero, float_repr, float_round, float_split_str class TestFloatPrecision(TransactionCase): @@ -111,7 +111,7 @@ class TestFloatPrecision(TransactionCase): # Note: max precision for double floats is 53 bits of precision or # 17 significant decimal digits for magnitude in range(7): - for frac, exp, prec in pycompat.izip(fractions, expecteds, precisions): + for frac, exp, prec in zip(fractions, expecteds, precisions): for sign in [-1,1]: for x in range(0, 10000, 97): n = x * 10 ** magnitude diff --git a/odoo/addons/base/tests/test_func.py b/odoo/addons/base/tests/test_func.py index 1b630060d7f..b0b540acb5d 100644 --- a/odoo/addons/base/tests/test_func.py +++ b/odoo/addons/base/tests/test_func.py @@ -5,7 +5,7 @@ import functools import unittest from odoo.tests.common import tagged -from odoo.tools import frozendict, pycompat +from odoo.tools import frozendict from odoo.tools.func import compose @@ -18,7 +18,7 @@ class TestCompose(unittest.TestCase): def test_decorator(self): """ ensure compose() can be partially applied as a decorator """ - @functools.partial(compose, pycompat.text_type) + @functools.partial(compose, str) def mul(a, b): return a * b diff --git a/odoo/addons/base/tests/test_orm.py b/odoo/addons/base/tests/test_orm.py index af515299d21..f51f928ab16 100644 --- a/odoo/addons/base/tests/test_orm.py +++ b/odoo/addons/base/tests/test_orm.py @@ -5,7 +5,7 @@ from collections import defaultdict from odoo.exceptions import AccessError, MissingError from odoo.tests.common import TransactionCase -from odoo.tools import mute_logger, pycompat +from odoo.tools import mute_logger class TestORM(TransactionCase): @@ -243,7 +243,7 @@ class TestORM(TransactionCase): records = self.env['res.bank'].create(vals_list) self.assertEqual(len(records), len(vals_list)) - for record, vals in pycompat.izip(records, vals_list): + for record, vals in zip(records, vals_list): self.assertEqual(record.name, vals['name']) self.assertEqual(record.email, vals.get('email', False)) @@ -279,7 +279,7 @@ class TestInherits(TransactionCase): """ `default_get` cannot return a dictionary or a new id """ defaults = self.env['res.users'].default_get(['partner_id']) if 'partner_id' in defaults: - self.assertIsInstance(defaults['partner_id'], (bool, pycompat.integer_types)) + self.assertIsInstance(defaults['partner_id'], (bool, int)) def test_create(self): """ creating a user should automatically create a new partner """ diff --git a/odoo/addons/base/tests/test_res_config.py b/odoo/addons/base/tests/test_res_config.py index 0f634b36cb3..70d1aed99b8 100644 --- a/odoo/addons/base/tests/test_res_config.py +++ b/odoo/addons/base/tests/test_res_config.py @@ -5,7 +5,6 @@ import logging from odoo import exceptions from odoo.tests.common import TransactionCase, tagged -from odoo.tools import pycompat _logger = logging.getLogger(__name__) @@ -46,8 +45,8 @@ class TestResConfig(TransactionCase): # Check types self.assertIsInstance(res, tuple) self.assertEqual(len(res), 2, "The result should contain 2 elements") - self.assertIsInstance(res[0], pycompat.string_types) - self.assertIsInstance(res[1], pycompat.integer_types) + self.assertIsInstance(res[0], str) + self.assertIsInstance(res[1], int) # Check returned values self.assertEqual(res[0], self.expected_path) @@ -58,7 +57,7 @@ class TestResConfig(TransactionCase): res = self.ResConfig.get_option_name(self.full_field_name) # Check type - self.assertIsInstance(res, pycompat.string_types) + self.assertIsInstance(res, str) # Check returned value self.assertEqual(res, self.expected_name) diff --git a/odoo/addons/base/tests/test_translate.py b/odoo/addons/base/tests/test_translate.py index c9d7f35ec4c..11bdf3d1cc8 100644 --- a/odoo/addons/base/tests/test_translate.py +++ b/odoo/addons/base/tests/test_translate.py @@ -3,7 +3,6 @@ import unittest -from odoo.tools import pycompat from odoo.tools import mute_logger from odoo.tools.translate import quote, unquote, xml_translate, html_translate from odoo.tests.common import TransactionCase, tagged @@ -319,7 +318,7 @@ class TestXMLTranslation(TransactionCase): 'arch': archf % terms, }) for lang, trans_terms in kwargs.items(): - for src, val in pycompat.izip(terms, trans_terms): + for src, val in zip(terms, trans_terms): self.env['ir.translation'].create({ 'type': 'model_terms', 'name': 'ir.ui.view,arch_db', diff --git a/odoo/addons/test_impex/models.py b/odoo/addons/test_impex/models.py index 410b1df7bbf..45cf4af4402 100644 --- a/odoo/addons/test_impex/models.py +++ b/odoo/addons/test_impex/models.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 def selection_fn(model): @@ -51,7 +50,7 @@ for name, field in MODELS: @api.model def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): - if isinstance(name, pycompat.string_types) and name.split(':')[0] == self._name: + if isinstance(name, str) and name.split(':')[0] == self._name: record_ids = self._search([('value', operator, int(name.split(':')[1]))], access_rights_uid=name_get_uid) return self.browse(record_ids).name_get() else: @@ -73,7 +72,7 @@ class One2ManyChild(models.Model): @api.model def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): - if isinstance(name, pycompat.string_types) and name.split(':')[0] == self._name: + if isinstance(name, str) and name.split(':')[0] == self._name: record_ids = self._search([('value', operator, int(name.split(':')[1]))], access_rights_uid=name_get_uid) return self.browse(record_ids).name_get() else: @@ -132,7 +131,7 @@ class Many2ManyChild(models.Model): @api.model def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): - if isinstance(name, pycompat.string_types) and name.split(':')[0] == self._name: + if isinstance(name, str) and name.split(':')[0] == self._name: record_ids = self._search([('value', operator, int(name.split(':')[1]))], access_rights_uid=name_get_uid) return self.browse(record_ids).name_get() else: diff --git a/odoo/addons/test_impex/tests/test_export.py b/odoo/addons/test_impex/tests/test_export.py index f44da3ef838..058d7581bf2 100644 --- a/odoo/addons/test_impex/tests/test_export.py +++ b/odoo/addons/test_impex/tests/test_export.py @@ -6,7 +6,6 @@ import pstats from cProfile import Profile from odoo.tests import common -from odoo.tools import pycompat class CreatorCase(common.TransactionCase): @@ -88,7 +87,7 @@ class test_integer_field(CreatorCase): def test_huge(self): self.assertEqual( self.export(2**31-1), - [[pycompat.text_type(2**31-1)]]) + [[str(2**31-1)]]) class test_float_field(CreatorCase): @@ -338,7 +337,7 @@ class test_m2o(CreatorCase): record = self.env['export.integer'].create({'value': 42}) self.assertEqual( self.export(record.id, fields=['value/.id', 'value/value']), - [[pycompat.text_type(record.id), u'42']]) + [[str(record.id), '42']]) def test_external_id(self): record = self.env['export.integer'].create({'value': 42}) @@ -537,9 +536,9 @@ class test_o2m_multiple(CreatorCase): """ fields = ['const', 'child1/value', 'child2/value'] child1 = [(0, False, {'value': v, 'str': 'record%.02d' % index}) - for index, v in pycompat.izip(itertools.count(), [4, 42, 36, 4, 13])] + for index, v in zip(itertools.count(), [4, 42, 36, 4, 13])] child2 = [(0, False, {'value': v, 'str': 'record%.02d' % index}) - for index, v in pycompat.izip(itertools.count(10), [8, 12, 8, 55, 33, 13])] + for index, v in zip(itertools.count(10), [8, 12, 8, 55, 33, 13])] self.assertEqual( self.export(child1=child1, child2=False, fields=fields), diff --git a/odoo/addons/test_new_api/models.py b/odoo/addons/test_new_api/models.py index a35c886b905..90edf910944 100644 --- a/odoo/addons/test_new_api/models.py +++ b/odoo/addons/test_new_api/models.py @@ -5,7 +5,6 @@ import datetime from odoo import models, fields, api, _ from odoo.exceptions import AccessError, ValidationError -from odoo.tools import pycompat class Category(models.Model): @@ -51,7 +50,7 @@ class Category(models.Model): categories.append(category[0]) categories.append(self) # assign parents following sequence - for parent, child in pycompat.izip(categories, categories[1:]): + for parent, child in zip(categories, categories[1:]): if parent and child: child.parent = parent # assign name of last category, and reassign display_name (to normalize it) diff --git a/odoo/addons/test_new_api/tests/test_attributes.py b/odoo/addons/test_new_api/tests/test_attributes.py index b37afe7e30d..94a048f2554 100644 --- a/odoo/addons/test_new_api/tests/test_attributes.py +++ b/odoo/addons/test_new_api/tests/test_attributes.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- from odoo.tests import common -from odoo.tools import pycompat ANSWER_TO_ULTIMATE_QUESTION = 42 @@ -17,7 +16,7 @@ class TestAttributes(common.TransactionCase): self.assertTrue(hasattr(instance, 'unknown')) # Is it the right type ? - self.assertIsInstance(instance.unknown, pycompat.integer_types) + self.assertIsInstance(instance.unknown, int) # Is it the right value, in case of, we don't know ;-) self.assertEqual(instance.unknown, ANSWER_TO_ULTIMATE_QUESTION) diff --git a/odoo/addons/test_new_api/tests/test_new_fields.py b/odoo/addons/test_new_api/tests/test_new_fields.py index 021fad63e39..358efcb575f 100644 --- a/odoo/addons/test_new_api/tests/test_new_fields.py +++ b/odoo/addons/test_new_api/tests/test_new_fields.py @@ -6,7 +6,7 @@ from datetime import date, datetime, time from odoo import fields from odoo.exceptions import AccessError, UserError from odoo.tests import common -from odoo.tools import mute_logger, float_repr, pycompat +from odoo.tools import mute_logger, float_repr from odoo.tools.date_utils import add, subtract, start_of, end_of @@ -18,8 +18,8 @@ class TestFields(common.TransactionCase): discussion = self.env.ref('test_new_api.discussion_0') # read field as a record attribute or as a record item - self.assertIsInstance(discussion.name, pycompat.string_types) - self.assertIsInstance(discussion['name'], pycompat.string_types) + self.assertIsInstance(discussion.name, str) + self.assertIsInstance(discussion['name'], str) self.assertEqual(discussion['name'], discussion.name) # read it with method read() diff --git a/odoo/addons/test_performance/tests/test_performance.py b/odoo/addons/test_performance/tests/test_performance.py index e81c1175265..7ea5fbcdadc 100644 --- a/odoo/addons/test_performance/tests/test_performance.py +++ b/odoo/addons/test_performance/tests/test_performance.py @@ -5,7 +5,7 @@ from collections import defaultdict import json from odoo.tests.common import TransactionCase, users, warmup -from odoo.tools import pycompat, mute_logger +from odoo.tools import mute_logger class TestPerformance(TransactionCase): @@ -399,7 +399,7 @@ class TestPerformance(TransactionCase): model.invalidate_cache() result = model.read_group([], ['partner_id', 'value'], ['partner_id']) self.assertEqual(len(result), len(expected)) - for res, exp in pycompat.izip(result, expected): + for res, exp in zip(result, expected): self.assertEqual(res['__domain'], exp['__domain']) self.assertEqual(res['partner_id'][0], exp['partner_id'][0]) self.assertEqual(res['partner_id_count'], exp['partner_id_count']) diff --git a/odoo/fields.py b/odoo/fields.py index d877cd71f87..5a523f28fb9 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -496,7 +496,7 @@ class Field(MetaField('DummyField', (object,), {})): deps = getattr(func, '_depends', ()) return deps(model) if callable(deps) else deps - if isinstance(self.compute, pycompat.string_types): + if isinstance(self.compute, str): # if the compute method has been overridden, concatenate all their _depends self.depends = tuple( dep @@ -517,7 +517,7 @@ class Field(MetaField('DummyField', (object,), {})): def _setup_related_full(self, model): """ Setup the attributes of a related field. """ # fix the type of self.related if necessary - if isinstance(self.related, pycompat.string_types): + if isinstance(self.related, str): self.related = tuple(self.related.split('.')) # determine the chain of fields, and make sure they are all set up @@ -604,7 +604,7 @@ class Field(MetaField('DummyField', (object,), {})): for name in self.related[:-1]: values = [first(value[name]) for value in values] # assign final values to records - for record, value in pycompat.izip(records, values): + for record, value in zip(records, values): record[self.name] = value[self.related_field.name] def _inverse_related(self, records): @@ -791,7 +791,7 @@ class Field(MetaField('DummyField', (object,), {})): """ Convert ``value`` from the ``write`` format to the SQL format. """ if value is None or value is False: return None - return pycompat.to_native(value) + return pycompat.to_text(value) def convert_to_cache(self, value, record, validate=True): """ Convert ``value`` to the cache format; ``value`` may come from an @@ -1028,7 +1028,7 @@ class Field(MetaField('DummyField', (object,), {})): for field in fields: for record in records: cache.set(record, field, field.convert_to_cache(False, record, validate=False)) - if isinstance(self.compute, pycompat.string_types): + if isinstance(self.compute, str): getattr(records, self.compute)() else: self.compute(records) @@ -1062,7 +1062,7 @@ class Field(MetaField('DummyField', (object,), {})): # HACK: if result is in the wrong cache, copy values if recs.env != env: computed = record._field_computed[self] - for source, target in pycompat.izip(recs, recs.with_env(env)): + for source, target in zip(recs, recs.with_env(env)): try: values = {f.name: source[f.name] for f in computed} target._cache.update(target._convert_to_cache(values, validate=False)) @@ -1100,14 +1100,14 @@ class Field(MetaField('DummyField', (object,), {})): def determine_inverse(self, records): """ Given the value of ``self`` on ``records``, inverse the computation. """ - if isinstance(self.inverse, pycompat.string_types): + if isinstance(self.inverse, str): getattr(records, self.inverse)() else: self.inverse(records) def determine_domain(self, records, operator, value): """ Return a domain representing a condition on ``self``. """ - if isinstance(self.search, pycompat.string_types): + if isinstance(self.search, str): return getattr(records, self.search)(operator, value) else: return self.search(records, operator, value) @@ -1773,14 +1773,14 @@ class Binary(Field): if isinstance(value, bytes): return psycopg2.Binary(value) try: - return psycopg2.Binary(pycompat.text_type(value).encode('ascii')) + return psycopg2.Binary(str(value).encode('ascii')) except UnicodeEncodeError: raise UserError(_("ASCII characters are required for %s in %s") % (value, self.name)) def convert_to_cache(self, value, record, validate=True): if isinstance(value, _BINARY): return bytes(value) - if isinstance(value, pycompat.integer_types) and \ + if isinstance(value, int) and \ (record._context.get('bin_size') or record._context.get('bin_size_' + self.name)): # If the client requests only the size of the field, we return that @@ -1912,7 +1912,7 @@ class Selection(Field): translated according to context language """ selection = self.selection - if isinstance(selection, pycompat.string_types): + if isinstance(selection, str): return getattr(env[self.model_name], selection)() if callable(selection): return selection(env[self.model_name]) @@ -1929,7 +1929,7 @@ class Selection(Field): def get_values(self, env): """ return a list of the possible values """ selection = self.selection - if isinstance(selection, pycompat.string_types): + if isinstance(selection, str): selection = getattr(env[self.model_name], selection)() elif callable(selection): selection = selection(env[self.model_name]) @@ -1980,7 +1980,7 @@ class Reference(Selection): if isinstance(value, BaseModel): if not validate or (value._name in self.get_values(record.env) and len(value) <= 1): return process(value._name, value.id) if value else False - elif isinstance(value, pycompat.string_types): + elif isinstance(value, str): res_model, res_id = value.split(',') if record.env[res_model].browse(int(res_id)).exists(): return process(res_model, int(res_id)) @@ -2309,7 +2309,7 @@ class _RelationalMulti(_Relational): self.depends += tuple( self.name + '.' + arg[0] for arg in self.domain - if isinstance(arg, (tuple, list)) and isinstance(arg[0], pycompat.string_types) + if isinstance(arg, (tuple, list)) and isinstance(arg[0], str) ) @@ -2708,7 +2708,7 @@ class Many2many(_RelationalMulti): if to_create: # create lines in batch, and link them lines = comodel.create([vals for ids, vals in to_create]) - for line, (ids, vals) in pycompat.izip(lines, to_create): + for line, (ids, vals) in zip(lines, to_create): relation_add(ids, line.id) if to_delete: diff --git a/odoo/http.py b/odoo/http.py index d5650e4ef9b..3b44a7d2054 100644 --- a/odoo/http.py +++ b/odoo/http.py @@ -518,7 +518,7 @@ def route(route=None, **kw): if isinstance(response, Response) or f.routing_type == 'json': return response - if isinstance(response, (bytes, pycompat.text_type)): + if isinstance(response, (bytes, str)): return Response(response) if isinstance(response, werkzeug.exceptions.HTTPException): @@ -1330,7 +1330,7 @@ class Root(object): path_static = opj(addons_path, module, 'static') if manifest_path and os.path.isdir(path_static): manifest_data = open(manifest_path, 'rb').read() - manifest = ast.literal_eval(pycompat.to_native(manifest_data)) + manifest = ast.literal_eval(pycompat.to_text(manifest_data)) if not manifest.get('installable', True): continue manifest['addons_path'] = addons_path @@ -1405,7 +1405,7 @@ class Root(object): else: raise - if isinstance(result, (bytes, pycompat.text_type)): + if isinstance(result, (bytes, str)): response = Response(result, mimetype='text/html') else: response = result @@ -1579,7 +1579,7 @@ def send_file(filepath_or_fp, mimetype=None, as_attachment=False, filename=None, :param cache_timeout: the timeout in seconds for the headers. """ - if isinstance(filepath_or_fp, pycompat.string_types): + if isinstance(filepath_or_fp, str): if not filename: filename = os.path.basename(filepath_or_fp) file = open(filepath_or_fp, 'rb') @@ -1629,7 +1629,7 @@ def send_file(filepath_or_fp, mimetype=None, as_attachment=False, filename=None, mtime, size, adler32( - filename.encode('utf-8') if isinstance(filename, pycompat.text_type) + filename.encode('utf-8') if isinstance(filename, str) else filename ) & 0xffffffff )) diff --git a/odoo/models.py b/odoo/models.py index 1af6cd9c173..bbd4a67d1e1 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -52,7 +52,7 @@ from . import tools from .exceptions import AccessError, MissingError, ValidationError, UserError from .osv.query import Query from .tools import frozendict, lazy_classproperty, lazy_property, ormcache, \ - Collector, LastOrderedSet, OrderedSet, pycompat, groupby + Collector, LastOrderedSet, OrderedSet, groupby from .tools.config import config from .tools.func import frame_codeinfo from .tools.misc import CountingStream, clean_context, DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT @@ -182,7 +182,7 @@ class NewId(object): return False __nonzero__ = __bool__ -IdType = pycompat.integer_types + pycompat.string_types + (NewId,) +IdType = (int, str, NewId) # maximum number of prefetched records @@ -418,7 +418,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): # determine inherited models parents = cls._inherit - parents = [parents] if isinstance(parents, pycompat.string_types) else (parents or []) + parents = [parents] if isinstance(parents, str) else (parents or []) # determine the model's name name = cls._name or (len(parents) == 1 and parents[0]) or cls.__name__ @@ -980,7 +980,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): # copy non-relational fields to record dict record = {fnames[0]: value - for fnames, value in pycompat.izip(fields_, row) + for fnames, value in zip(fields_, row) if not is_relational(fnames[0])} # Get all following rows which have relational values attached to @@ -994,13 +994,13 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): # get only cells for this sub-field, should be strictly # non-empty, field path [None] is for name_get field - indices, subfields = pycompat.izip(*((index, fnames[1:] or [None]) + indices, subfields = zip(*((index, fnames[1:] or [None]) for index, fnames in enumerate(fields_) if fnames[0] == relfield)) # return all rows which have at least one value for the # subfields of relfield - relfield_data = [it for it in pycompat.imap(itemgetter_tuple(indices), record_span) if any(it)] + relfield_data = [it for it in map(itemgetter_tuple(indices), record_span) if any(it)] record[relfield] = [ subrecord for subrecord, _subinfo in comodel._extract_records(subfields, relfield_data, log=log) @@ -1033,7 +1033,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): # processing of response, but injects human readable in message exc_vals = dict(base, record=record, field=field_names[field]) record = dict(base, type=type, record=record, field=field, - message=pycompat.text_type(exception.args[0]) % exc_vals) + message=str(exception.args[0]) % exc_vals) if len(exception.args) > 1 and exception.args[1]: record.update(exception.args[1]) log(record) @@ -1528,7 +1528,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): provided domain <reference/orm/domains>`. """ res = self.search(args, count=True) - return res if isinstance(res, pycompat.integer_types) else len(res) + return res if isinstance(res, int) else len(res) @api.model @api.returns('self', @@ -1673,7 +1673,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 defaults.items(): - if self._fields[name].type == 'many2many' and value and isinstance(value[0], pycompat.integer_types): + if self._fields[name].type == 'many2many' and value and isinstance(value[0], int): # convert a list of ids into a list of commands defaults[name] = [(6, 0, value)] elif self._fields[name].type == 'one2many' and value and isinstance(value[0], dict): @@ -1948,7 +1948,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): value = False if value is None else value gb = groupby_dict.get(key) if gb and gb['type'] in ('date', 'datetime') and value: - if isinstance(value, pycompat.string_types): + if isinstance(value, str): dt_format = DEFAULT_SERVER_DATETIME_FORMAT if gb['type'] == 'datetime' else DEFAULT_SERVER_DATE_FORMAT value = datetime.datetime.strptime(value, dt_format) if gb['tz_convert']: @@ -2061,7 +2061,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): """ result = self._read_group_raw(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) - groupby = [groupby] if isinstance(groupby, pycompat.string_types) else list(OrderedSet(groupby)) + groupby = [groupby] if isinstance(groupby, str) else list(OrderedSet(groupby)) dt = [ f for f in groupby if self._fields[f.split(':')[0]].type in ('date', 'datetime') # e.g. 'date:month' @@ -2085,7 +2085,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): query = self._where_calc(domain) 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 = [groupby] if isinstance(groupby, str) else list(OrderedSet(groupby)) groupby_list = groupby[:1] if lazy else groupby annotated_groupbys = [self._read_group_process_groupby(gb, query) for gb in groupby_list] groupby_fields = [g['field'] for g in annotated_groupbys] @@ -3276,7 +3276,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): # groups by dependence (in case they depend on each other) field_groups = sorted( (fields for _inv, fields in groupby(inverse_fields, attrgetter('inverse'))), - key=lambda fields: min(pycompat.imap(self.pool.field_sequence, fields)), + key=lambda fields: min(map(self.pool.field_sequence, fields)), ) for fields in field_groups: # If a field is not stored, its inverse method will probably @@ -3497,7 +3497,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): data['inherited'][model_name] for data in parent_data_list ]) - for parent, data in pycompat.izip(parents, parent_data_list): + for parent, data in zip(parents, parent_data_list): data['stored'][parent_name] = parent.id # create records with stored fields @@ -3510,7 +3510,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): # by dependence (in case they depend on each other) field_groups = sorted( (fields for _inv, fields in groupby(inversed_fields, attrgetter('inverse'))), - key=lambda fields: min(pycompat.imap(self.pool.field_sequence, fields)), + key=lambda fields: min(map(self.pool.field_sequence, fields)), ) for fields in field_groups: # determine which records to inverse for those fields @@ -3606,7 +3606,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): # the new records records = self.browse(ids) - for data, record in pycompat.izip(data_list, records): + for data, record in zip(data_list, records): data['record'] = record # update parent_path @@ -3625,7 +3625,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): for field in sorted(other_fields, key=attrgetter('_sequence')): field.create([ (other, data['stored'][field.name]) - for other, data in pycompat.izip(others, data_list) + for other, data in zip(others, data_list) if field.name in data['stored'] ]) @@ -3801,7 +3801,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): # create records records = self.create([data['values'] for data in to_create]) - for data, record in pycompat.izip(to_create, records): + for data, record in zip(to_create, records): data['record'] = record # create or update XMLIDs @@ -4186,7 +4186,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): # foreseen in copy_data() old_lines = old[name].sorted(key='id') new_lines = new[name].sorted(key='id') - for (old_line, new_line) in pycompat.izip(old_lines, new_lines): + for (old_line, new_line) in zip(old_lines, new_lines): # don't pass excluded as it is not about those lines old_line.copy_translations(new_line) @@ -4247,7 +4247,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): """ ids, new_ids = [], [] for i in self._ids: - (ids if isinstance(i, pycompat.integer_types) else new_ids).append(i) + (ids if isinstance(i, int) else new_ids).append(i) if not ids: return self query = """SELECT id FROM "%s" WHERE id IN %%s""" % self._table @@ -4791,7 +4791,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): """ if not func: return self # support for an empty path of fields - if isinstance(func, pycompat.string_types): + if isinstance(func, str): recs = self for name in func.split('.'): recs = recs._mapped_func(operator.itemgetter(name)) @@ -4819,7 +4819,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): :param func: a function or a dot-separated sequence of field names """ - if isinstance(func, pycompat.string_types): + if isinstance(func, str): name = func func = lambda rec: any(rec.mapped(name)) return self.browse([rec.id for rec in self if func(rec)]) @@ -4836,7 +4836,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): if key is None: recs = self.search([('id', 'in', self.ids)]) return self.browse(reversed(recs._ids)) if reverse else recs - if isinstance(key, pycompat.string_types): + if isinstance(key, str): key = itemgetter(key) return self.browse(item.id for item in sorted(self, key=key, reverse=reverse)) @@ -4924,7 +4924,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): """ if isinstance(item, BaseModel) and self._name == item._name: return len(item) == 1 and item.id in self._ids - elif isinstance(item, pycompat.string_types): + elif isinstance(item, str): return item in self._fields else: raise TypeError("Mixing apples and oranges: %s in %s" % (item, self)) @@ -5042,7 +5042,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): rs = inst[10:20] # subset of inst nm = rs['name'] # name of first record in inst """ - if isinstance(key, pycompat.string_types): + if isinstance(key, str): # important: one must call the field's getter return self._fields[key].__get__(self, type(self)) elif isinstance(key, slice): diff --git a/odoo/modules/migration.py b/odoo/modules/migration.py index 57d217e770d..4081232b5ff 100644 --- a/odoo/modules/migration.py +++ b/odoo/modules/migration.py @@ -13,7 +13,6 @@ from odoo.modules.module import get_resource_path import odoo.release as release import odoo.tools as tools from odoo.tools.parse_version import parse_version -from odoo.tools import pycompat if pycompat.PY2: import imp diff --git a/odoo/modules/module.py b/odoo/modules/module.py index 93be467b0f3..4f7f80ca396 100644 --- a/odoo/modules/module.py +++ b/odoo/modules/module.py @@ -324,13 +324,13 @@ def load_information_from_description_file(module, mod_path=None): 'summary': '', 'website': '', } - info.update(pycompat.izip( + info.update(zip( 'depends data demo test init_xml update_xml demo_xml'.split(), iter(list, None))) f = tools.file_open(manifest_file, mode='rb') try: - info.update(ast.literal_eval(pycompat.to_native(f.read()))) + info.update(ast.literal_eval(pycompat.to_text(f.read()))) finally: f.close() diff --git a/odoo/osv/expression.py b/odoo/osv/expression.py index 483f325322c..1eecceeca6c 100644 --- a/odoo/osv/expression.py +++ b/odoo/osv/expression.py @@ -403,7 +403,7 @@ def normalize_leaf(element): def is_operator(element): """ Test whether an object is a valid domain operator. """ - return isinstance(element, pycompat.string_types) and element in DOMAIN_OPERATORS + return isinstance(element, str) and element in DOMAIN_OPERATORS def is_leaf(element, internal=False): @@ -424,7 +424,7 @@ def is_leaf(element, internal=False): return (isinstance(element, tuple) or isinstance(element, list)) \ and len(element) == 3 \ and element[1] in INTERNAL_OPS \ - and ((isinstance(element[0], pycompat.string_types) and element[0]) + and ((isinstance(element[0], str) and element[0]) or tuple(element) in (TRUE_LEAF, FALSE_LEAF)) @@ -723,11 +723,11 @@ class expression(object): return the list of related ids """ names = [] - if isinstance(value, pycompat.string_types): + if isinstance(value, str): names = [value] - elif value and isinstance(value, (tuple, list)) and all(isinstance(item, pycompat.string_types) for item in value): + elif value and isinstance(value, (tuple, list)) and all(isinstance(item, str) for item in value): names = value - elif isinstance(value, pycompat.integer_types): + elif isinstance(value, int): if not value: # given this nonsensical domain, it is generally cheaper to # interpret False as [], so that "X child_of False" will @@ -955,7 +955,7 @@ class expression(object): if right is not False: # determine ids2 in comodel - if isinstance(right, pycompat.string_types): + if isinstance(right, str): op2 = (TERM_OPERATORS_NEGATION[operator] if operator in NEGATIVE_TERM_OPERATORS else operator) ids2 = [x[0] for x in comodel.name_search(right, domain or [], op2, limit=None)] @@ -1012,7 +1012,7 @@ class expression(object): elif right is not False: # determine ids2 in comodel - if isinstance(right, pycompat.string_types): + if isinstance(right, str): domain = field.domain if callable(domain): domain = domain(model) @@ -1064,8 +1064,8 @@ class expression(object): res_ids.append(False) # TODO this should not be appended if False was in 'right' return left, 'in', res_ids # resolve string-based m2o criterion into IDs - if isinstance(right, pycompat.string_types) or \ - right and isinstance(right, (tuple, list)) and all(isinstance(item, pycompat.string_types) for item in right): + if isinstance(right, str) or \ + right and isinstance(right, (tuple, list)) and all(isinstance(item, str) for item in right): push(create_substitution_leaf(leaf, _get_expression(comodel, left, right, operator), model)) else: # right == [] or right == False and all other cases are handled by __leaf_to_sql() @@ -1097,7 +1097,7 @@ class expression(object): else: if field.type == 'datetime' and right: - if isinstance(right, pycompat.string_types) and len(right) == 10: + if isinstance(right, str) and len(right) == 10: if operator in ('>', '<='): right += ' 23:59:59' else: @@ -1267,7 +1267,7 @@ class expression(object): query = '(%s %s %s)' % (unaccent(column + cast), sql_operator, unaccent(format)) if need_wildcard: - native_str = pycompat.to_native(right) + native_str = pycompat.to_text(right) if not native_str: query = '(%s OR %s."%s" IS NULL)' % (query, table_alias, left) params = ['%%%s%%' % native_str] diff --git a/odoo/osv/orm.py b/odoo/osv/orm.py index 0d5c7e66fb1..e316949dae1 100644 --- a/odoo/osv/orm.py +++ b/odoo/osv/orm.py @@ -3,7 +3,6 @@ import warnings from lxml import etree -from odoo.tools import pycompat from ..exceptions import except_orm from ..models import ( MetaModel, @@ -125,7 +124,7 @@ def setup_modifiers(node, field=None, context=None, in_tree_view=False): def test_modifiers(what, expected): modifiers = {} - if isinstance(what, pycompat.string_types): + if isinstance(what, str): node = etree.fromstring(what) transfer_node_to_modifiers(node, modifiers) simplify_modifiers(modifiers) diff --git a/odoo/service/db.py b/odoo/service/db.py index df641cb2c50..0cc86e4ee66 100644 --- a/odoo/service/db.py +++ b/odoo/service/db.py @@ -25,7 +25,6 @@ import odoo.sql_db import odoo.tools from odoo.sql_db import db_connect from odoo.release import version_info -from odoo.tools import pycompat _logger = logging.getLogger(__name__) @@ -259,7 +258,7 @@ def exp_restore(db_name, data, copy=False): @check_db_management_enabled def restore_db(db, dump_file, copy=False): - assert isinstance(db, pycompat.string_types) + assert isinstance(db, str) if exp_db_exist(db): _logger.info('RESTORE DB: %s already exists', db) raise Exception("Database already exists") diff --git a/odoo/sql_db.py b/odoo/sql_db.py index afa396148f0..a21890f69f5 100644 --- a/odoo/sql_db.py +++ b/odoo/sql_db.py @@ -41,7 +41,6 @@ psycopg2.extensions.register_type(psycopg2.extensions.new_type((700, 701, 1700,) from . import tools from .tools.func import frame_codeinfo -from .tools import pycompat from .tools import parse_version as pv if pv(psycopg2.__version__) < pv('2.7'): @@ -52,8 +51,7 @@ if pv(psycopg2.__version__) < pv('2.7'): raise ValueError("A string literal cannot contain NUL (0x00) characters.") return QuotedString(adapted) - for type_ in pycompat.string_types: - psycopg2.extensions.register_adapter(type_, adapt_string) + psycopg2.extensions.register_adapter(str, adapt_string) from datetime import timedelta import threading diff --git a/odoo/tests/common.py b/odoo/tests/common.py index 0bcd4d4c967..89a9473e432 100644 --- a/odoo/tests/common.py +++ b/odoo/tests/common.py @@ -33,7 +33,6 @@ from lxml import etree, html from odoo.models import BaseModel from odoo.osv.expression import normalize_domain -from odoo.tools import pycompat from odoo.tools import single_email_re from odoo.tools.misc import find_in_path from odoo.tools.safe_eval import safe_eval @@ -1091,7 +1090,7 @@ class Form(object): if isinstance(view, BaseModel): assert view._name == 'ir.ui.view', "the view parameter must be a view id, xid or record, got %s" % view view_id = view.id - elif isinstance(view, pycompat.string_types): + elif isinstance(view, str): view_id = env.ref(view).id else: view_id = view or False diff --git a/odoo/tools/appdirs.py b/odoo/tools/appdirs.py index 5bd5afb11cb..67ba75625c1 100644 --- a/odoo/tools/appdirs.py +++ b/odoo/tools/appdirs.py @@ -13,7 +13,6 @@ from __future__ import print_function # http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120 # - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html # - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html -from . import pycompat __version_info__ = (1, 3, 0) __version__ = '.'.join(str(v) for v in __version_info__) @@ -392,7 +391,7 @@ def _get_win_folder_with_pywin32(csidl_name): # not return unicode strings when there is unicode data in the # path. try: - dir = pycompat.text_type(dir) + dir = str(dir) # Downgrade to short path name if have highbit chars. See # <http://bugs.activestate.com/show_bug.cgi?id=85099>. diff --git a/odoo/tools/cache.py b/odoo/tools/cache.py index 052f89545a2..8481df0d33d 100644 --- a/odoo/tools/cache.py +++ b/odoo/tools/cache.py @@ -8,8 +8,6 @@ from decorator import decorator from inspect import formatargspec, getargspec import logging -from . import pycompat - unsafe_eval = eval _logger = logging.getLogger(__name__) @@ -139,7 +137,7 @@ class ormcache_multi(ormcache): def determine_key(self): """ Determine the function that computes a cache key from arguments. """ assert self.skiparg is None, "ormcache_multi() no longer supports skiparg" - assert isinstance(self.multi, pycompat.string_types), "ormcache_multi() parameter multi must be an argument name" + assert isinstance(self.multi, str), "ormcache_multi() parameter multi must be an argument name" super(ormcache_multi, self).determine_key() diff --git a/odoo/tools/config.py b/odoo/tools/config.py index 47c5b633cff..812e4e2adc6 100644 --- a/odoo/tools/config.py +++ b/odoo/tools/config.py @@ -13,7 +13,7 @@ import os import sys import odoo from .. import release, conf, loglevels -from . import appdirs, pycompat +from . import appdirs from passlib.context import CryptContext crypt_context = CryptContext(schemes=['pbkdf2_sha512', 'plaintext'], @@ -418,10 +418,10 @@ class configmanager(object): if getattr(opt, arg): self.options[arg] = getattr(opt, arg) # ... or keep, but cast, the config file value. - elif isinstance(self.options[arg], pycompat.string_types) and self.casts[arg].type in optparse.Option.TYPE_CHECKER: + elif isinstance(self.options[arg], str) and self.casts[arg].type in optparse.Option.TYPE_CHECKER: self.options[arg] = optparse.Option.TYPE_CHECKER[self.casts[arg].type](self.casts[arg], arg, self.options[arg]) - if isinstance(self.options['log_handler'], pycompat.string_types): + if isinstance(self.options['log_handler'], str): self.options['log_handler'] = self.options['log_handler'].split(',') self.options['log_handler'].extend(opt.log_handler) @@ -453,7 +453,7 @@ class configmanager(object): if getattr(opt, arg) is not None: self.options[arg] = getattr(opt, arg) # ... or keep, but cast, the config file value. - elif isinstance(self.options[arg], pycompat.string_types) and self.casts[arg].type in optparse.Option.TYPE_CHECKER: + elif isinstance(self.options[arg], str) and self.casts[arg].type in optparse.Option.TYPE_CHECKER: self.options[arg] = optparse.Option.TYPE_CHECKER[self.casts[arg].type](self.casts[arg], arg, self.options[arg]) self.options['root_path'] = os.path.abspath(os.path.expanduser(os.path.expandvars(os.path.join(os.path.dirname(__file__), '..')))) @@ -563,7 +563,7 @@ class configmanager(object): def save(self): p = ConfigParser.RawConfigParser() - loglevelnames = dict(pycompat.izip(self._LOGLEVELS.values(), self._LOGLEVELS)) + loglevelnames = dict(zip(self._LOGLEVELS.values(), self._LOGLEVELS)) p.add_section('options') for opt in sorted(self.options): if opt in ('version', 'language', 'translate_out', 'translate_in', 'overwrite_existing_translations', 'init', 'update'): @@ -609,7 +609,7 @@ class configmanager(object): def __setitem__(self, key, value): self.options[key] = value - if key in self.options and isinstance(self.options[key], pycompat.string_types) and \ + if key in self.options and isinstance(self.options[key], str) and \ key in self.casts and self.casts[key].type in optparse.Option.TYPE_CHECKER: self.options[key] = optparse.Option.TYPE_CHECKER[self.casts[key].type](self.casts[key], key, self.options[key]) diff --git a/odoo/tools/convert.py b/odoo/tools/convert.py index 2e984a39618..36e1bdcd4b5 100644 --- a/odoo/tools/convert.py +++ b/odoo/tools/convert.py @@ -128,7 +128,7 @@ def _eval_xml(self, node, env): # So funny story: in Python 3, bytes(n: int) returns a # bytestring of n nuls. In Python 2 it obviously returns the # stringified number, which is what we're expecting here - s = s.replace(found, pycompat.text_type(self.idref[id])) + s = s.replace(found, str(self.idref[id])) s = s.replace('%%', '%') # Quite weird but it's for (somewhat) backward compatibility sake return s @@ -575,7 +575,7 @@ form: module.record_id""" % (xml_id,) f_val = int(f_val) elif model._fields[f_name].type in ['float', 'monetary']: f_val = float(f_val) - elif model._fields[f_name].type == 'boolean' and isinstance(f_val, pycompat.string_types): + elif model._fields[f_name].type == 'boolean' and isinstance(f_val, str): f_val = str2bool(f_val) res[f_name] = f_val @@ -793,7 +793,7 @@ def convert_xml_import(cr, module, xmlfile, idref=None, mode='init', noupdate=Fa _logger.info(ustr(relaxng.error_log.last_error)) raise - if isinstance(xmlfile, pycompat.string_types): + if isinstance(xmlfile, str): xml_filename = xmlfile else: xml_filename = xmlfile.name diff --git a/odoo/tools/float_utils.py b/odoo/tools/float_utils.py index 041a87cabbe..c5c2946a5ce 100644 --- a/odoo/tools/float_utils.py +++ b/odoo/tools/float_utils.py @@ -4,7 +4,6 @@ from __future__ import print_function import math -from odoo.tools import pycompat if not pycompat.PY2: import builtins @@ -224,7 +223,7 @@ if __name__ == "__main__": expecteds = ['.00', '.02', '.01', '.68', '.67', '.46', '.456', '.4556'] precisions = [2, 2, 2, 2, 2, 2, 3, 4] for magnitude in range(7): - for frac, exp, prec in pycompat.izip(fractions, expecteds, precisions): + for frac, exp, prec in zip(fractions, expecteds, precisions): for sign in [-1,1]: for x in range(0, 10000, 97): n = x * 10**magnitude diff --git a/odoo/tools/image.py b/odoo/tools/image.py index 2814aaaaa3f..0cf79978193 100644 --- a/odoo/tools/image.py +++ b/odoo/tools/image.py @@ -9,8 +9,6 @@ from PIL import ImageEnhance from random import randrange # Preload PIL with the minimal subset of image formats we need -from odoo.tools import pycompat - Image.preinit() Image._initialized = 2 @@ -291,7 +289,7 @@ def image_get_resized_images(base64_source, return_big=False, return_medium=True size_big = sizes.get(big_name, (1024, 1024)) size_medium = sizes.get(medium_name, (128, 128)) size_small = sizes.get(small_name, (64, 64)) - if isinstance(base64_source, pycompat.text_type): + if isinstance(base64_source, str): base64_source = base64_source.encode('ascii') if return_big: return_dict[big_name] = image_resize_image_big(base64_source, avoid_if_small=avoid_resize_big, size=size_big) diff --git a/odoo/tools/mail.py b/odoo/tools/mail.py index 3bb080094ab..847fcfcf2f3 100644 --- a/odoo/tools/mail.py +++ b/odoo/tools/mail.py @@ -16,7 +16,7 @@ from lxml import etree import odoo from odoo.loglevels import ustr -from odoo.tools import pycompat, misc +from odoo.tools import misc _logger = logging.getLogger(__name__) @@ -224,7 +224,7 @@ def html_sanitize(src, silent=True, sanitize_tags=True, sanitize_attributes=Fals # some corner cases make the parser crash (such as <SCRIPT/XSS SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT> in test_mail) cleaner = _Cleaner(**kwargs) cleaned = cleaner.clean_html(src) - assert isinstance(cleaned, pycompat.text_type) + assert isinstance(cleaned, str) # MAKO compatibility: $, { and } inside quotes are escaped, preventing correct mako execution cleaned = cleaned.replace(u'%24', u'$') cleaned = cleaned.replace(u'%7B', u'{') @@ -238,7 +238,7 @@ def html_sanitize(src, silent=True, sanitize_tags=True, sanitize_attributes=Fals # html considerations so real html content match database value cleaned.replace(u'\xa0', u' ') except etree.ParserError as e: - if u'empty' in pycompat.text_type(e): + if 'empty' in str(e): return u"" if not silent: raise diff --git a/odoo/tools/misc.py b/odoo/tools/misc.py index 762c07e535c..b165eb3a130 100644 --- a/odoo/tools/misc.py +++ b/odoo/tools/misc.py @@ -281,7 +281,7 @@ def flatten(list): """ r = [] for e in list: - if isinstance(e, (bytes, pycompat.text_type)) or not isinstance(e, collections.Iterable): + if isinstance(e, (bytes, str)) or not isinstance(e, collections.Iterable): r.append(e) else: r.extend(flatten(e)) @@ -304,7 +304,7 @@ def reverse_enumerate(l): File "<stdin>", line 1, in <module> StopIteration """ - return pycompat.izip(range(len(l)-1, -1, -1), reversed(l)) + return zip(range(len(l)-1, -1, -1), reversed(l)) def partition(pred, elems): """ Return a pair equivalent to: @@ -468,7 +468,7 @@ def human_size(sz): if not sz: return False units = ('bytes', 'Kb', 'Mb', 'Gb') - if isinstance(sz,pycompat.string_types): + if isinstance(sz, str): sz=len(sz) s, i = float(sz), 0 while s >= 1024 and i < len(units)-1: @@ -814,7 +814,7 @@ class mute_logger(object): def __enter__(self): for logger in self.loggers: - assert isinstance(logger, pycompat.string_types),\ + assert isinstance(logger, str),\ "A logger name must be a string, got %s" % type(logger) logging.getLogger(logger).addFilter(self) @@ -1148,7 +1148,7 @@ def formatLang(env, value, digits=None, grouping=True, monetary=False, dp=False, if not digits and digits is not 0: digits = DEFAULT_DIGITS - if isinstance(value, pycompat.string_types) and not value: + if isinstance(value, str) and not value: return '' lang = env.context.get('lang') or env.user.company_id.partner_id.lang or 'en_US' @@ -1178,7 +1178,7 @@ def format_date(env, value, lang_code=False, date_format=False): ''' if not value: return '' - if isinstance(value, pycompat.string_types): + if isinstance(value, str): if len(value) < DATE_LENGTH: return '' if len(value) > DATE_LENGTH: @@ -1198,7 +1198,7 @@ def format_date(env, value, lang_code=False, date_format=False): def _consteq(str1, str2): """ Constant-time string comparison. Suitable to compare bytestrings of fixed, known length only, because length difference is optimized. """ - return len(str1) == len(str2) and sum(ord(x)^ord(y) for x, y in pycompat.izip(str1, str2)) == 0 + return len(str1) == len(str2) and sum(ord(x)^ord(y) for x, y in zip(str1, str2)) == 0 consteq = getattr(passlib.utils, 'consteq', _consteq) diff --git a/odoo/tools/parse_version.py b/odoo/tools/parse_version.py index be509a1504f..f897c024505 100644 --- a/odoo/tools/parse_version.py +++ b/odoo/tools/parse_version.py @@ -7,8 +7,6 @@ from __future__ import print_function import re -from odoo.tools import pycompat - component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE) replace = {'pre':'c', 'preview':'c','-':'final-','_':'final-','rc':'c','dev':'@','saas':'','~':''}.get @@ -74,7 +72,7 @@ if __name__ == '__main__': if verbose: print(v, pv) - for a, b in pycompat.izip(pvs, pvs[1:]): + for a, b in zip(pvs, pvs[1:]): assert a < b, '%s < %s == %s' % (a, b, a < b) chk(('0', '4.2', '4.2.3.4', '5.0.0-alpha', '5.0.0-rc1', '5.0.0-rc1.1', '5.0.0_rc2', '5.0.0_rc3', '5.0.0'), False) diff --git a/odoo/tools/safe_eval.py b/odoo/tools/safe_eval.py index ccb2e3e25b4..813fd822e39 100644 --- a/odoo/tools/safe_eval.py +++ b/odoo/tools/safe_eval.py @@ -24,7 +24,6 @@ import logging import sys import werkzeug -from . import pycompat from .misc import ustr from . import pycompat @@ -273,7 +272,7 @@ _BUILTINS = { 'None': None, 'bytes': bytes, 'str': str, - 'unicode': pycompat.text_type, + 'unicode': str, 'bool': bool, 'int': int, 'float': float, diff --git a/odoo/tools/test_reports.py b/odoo/tools/test_reports.py index 803d9fc18c5..ef3e61ecb42 100644 --- a/odoo/tools/test_reports.py +++ b/odoo/tools/test_reports.py @@ -13,7 +13,7 @@ import tempfile from subprocess import Popen, PIPE from .. import api -from . import pycompat, ustr, config +from . import ustr, config from .safe_eval import safe_eval _logger = logging.getLogger(__name__) @@ -88,7 +88,7 @@ def try_report_action(cr, uid, action_id, active_model=None, active_ids=None, Eg. 'OK' or 'fa-print' :param our_module: the name of the calling module (string), like 'account' """ - if not our_module and isinstance(action_id, pycompat.string_types): + if not our_module and isinstance(action_id, str): if '.' in action_id: our_module = action_id.split('.', 1)[0] @@ -109,7 +109,7 @@ def try_report_action(cr, uid, action_id, active_model=None, active_ids=None, if not wiz_buttons: wiz_buttons = [] - if isinstance(action_id, pycompat.string_types): + if isinstance(action_id, str): if '.' in action_id: _, act_xmlid = action_id.split('.', 1) else: @@ -120,7 +120,7 @@ def try_report_action(cr, uid, action_id, active_model=None, active_ids=None, action = env.ref(action_id) act_model, act_id = action._name, action.id else: - assert isinstance(action_id, pycompat.integer_types) + assert isinstance(action_id, int) act_model = 'ir.action.act_window' # assume that act_id = action_id act_xmlid = '<%s>' % act_id @@ -134,7 +134,7 @@ def try_report_action(cr, uid, action_id, active_model=None, active_ids=None, if datas.get('id',False): context.update( {'active_id': datas.get('id',False), 'active_ids': datas.get('ids',[]), 'active_model': datas.get('model',False)}) context1 = action.get('context', {}) - if isinstance(context1, pycompat.string_types): + if isinstance(context1, str): context1 = safe_eval(context1, dict(context)) context.update(context1) env = env(context=context) diff --git a/odoo/tools/translate.py b/odoo/tools/translate.py index 3854e9436d4..40188738816 100644 --- a/odoo/tools/translate.py +++ b/odoo/tools/translate.py @@ -130,7 +130,7 @@ csv.register_dialect("UNIX", UNIX_LINE_TERMINATOR) # FIXME: holy shit this whole thing needs to be cleaned up hard it's a mess def encode(s): - assert isinstance(s, pycompat.text_type) + assert isinstance(s, str) return s # which elements are translated inline @@ -651,8 +651,8 @@ class PoFile(object): u"msgid %s\n" u"msgstr %s\n\n" ) % ( - quote(pycompat.text_type(source)), - quote(pycompat.text_type(trad)) + quote(str(source)), + quote(str(trad)) ) self.buffer.write(msg) @@ -1100,7 +1100,7 @@ def trans_load_data(cr, fileobj, fileformat, lang, lang_name=None, verbose=True, dic = dict.fromkeys(('type', 'name', 'res_id', 'src', 'value', 'comments', 'imd_model', 'imd_name', 'module')) dic['lang'] = lang - dic.update(pycompat.izip(fields, row)) + dic.update(zip(fields, row)) # ignore empty value that may be set from base language if not dic['value']: @@ -1124,8 +1124,8 @@ def trans_load_data(cr, fileobj, fileformat, lang, lang_name=None, verbose=True, if not res_id and dic['type'] != 'code': return - if isinstance(res_id, pycompat.integer_types) or \ - (isinstance(res_id, pycompat.string_types) and res_id.isdigit()): + if isinstance(res_id, int) or \ + (isinstance(res_id, str) and res_id.isdigit()): dic['res_id'] = int(res_id) if module_name: dic['module'] = module_name |
