From 7dd062f83552fa8ff96224c29d60bafc001d73d3 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 2 May 2017 12:07:30 +0200 Subject: [PATCH] [FIX] P3: text model types * remove references to basestring & unicode (use relevant pycompat helpers) * remove some str calls (either entirely or replaced by relevant helper, either text or native) * use better API to avoid unnecessary conversions * remove some XML declarations in views --- addons/anonymization/models/anonymization.py | 3 +- addons/base_import/models/base_import.py | 6 +- addons/board/models/board.py | 3 +- addons/bus/controllers/main.py | 6 +- addons/calendar/models/calendar.py | 17 +++--- addons/calendar/models/ir_attachment.py | 6 +- addons/calendar/models/mail_message.py | 4 +- addons/crm/wizard/base_partner_merge.py | 2 +- addons/document/models/ir_attachment.py | 13 ----- addons/hw_escpos/escpos/escpos.py | 4 +- addons/l10n_be_intrastat/wizard/xml_decl.py | 23 ++++---- addons/l10n_lu/scripts/tax2csv.py | 9 ++- addons/mail/controllers/main.py | 4 +- addons/mail/models/ir_model.py | 3 +- addons/mail/models/mail_thread.py | 27 +++++---- .../models/authorize_request.py | 2 +- .../payment_authorize/tests/test_authorize.py | 2 +- addons/product/models/product.py | 2 +- addons/product/models/product_template.py | 2 +- addons/stock/models/product.py | 4 +- addons/survey/controllers/main.py | 2 +- .../wizard/survey_email_compose_message.py | 3 +- addons/utm/models/utm.py | 3 +- addons/web/controllers/main.py | 4 +- addons/web_editor/controllers/main.py | 4 +- addons/web_editor/models/ir_qweb.py | 15 +++-- addons/web_editor/models/ir_ui_view.py | 2 +- addons/website/controllers/main.py | 2 +- addons/website/models/ir_ui_view.py | 2 +- addons/website/models/website.py | 9 +-- doc/_extensions/github_link.py | 4 +- doc/_extensions/odoo_ext/translator.py | 10 ++-- odoo/addons/base/ir/ir_fields.py | 10 ++-- odoo/addons/base/ir/ir_model.py | 9 +-- odoo/addons/base/ir/ir_qweb/__init__.py | 2 +- odoo/addons/base/ir/ir_qweb/fields.py | 27 +++++---- odoo/addons/base/ir/ir_qweb/ir_qweb.py | 2 +- odoo/addons/base/ir/ir_qweb/qweb.py | 55 +++++++++---------- odoo/addons/base/ir/ir_translation.py | 2 +- odoo/addons/base/ir/ir_ui_view.py | 10 ++-- odoo/addons/base/ir/ir_values.py | 6 +- odoo/addons/base/module/module.py | 2 +- odoo/addons/base/res/res_users.py | 6 +- odoo/addons/base/tests/test_func.py | 4 +- odoo/addons/base/tests/test_qweb.py | 2 +- odoo/addons/base/tests/test_res_config.py | 4 +- odoo/addons/test_impex/models.py | 7 ++- odoo/addons/test_impex/tests/test_export.py | 4 +- .../test_new_api/tests/test_new_fields.py | 6 +- odoo/fields.py | 45 ++++++--------- odoo/http.py | 18 +++--- odoo/loglevels.py | 19 ++++--- odoo/models.py | 46 ++++++++-------- odoo/osv/expression.py | 29 ++++------ odoo/osv/orm.py | 2 +- odoo/service/db.py | 3 +- odoo/tools/__init__.py | 2 +- odoo/tools/appdirs.py | 9 +-- odoo/tools/cache.py | 4 +- odoo/tools/config.py | 20 +++---- odoo/tools/convert.py | 5 +- odoo/tools/misc.py | 8 +-- odoo/tools/pycompat.py | 43 +++++++++++++++ odoo/tools/safe_eval.py | 4 +- odoo/tools/test_reports.py | 29 +++++----- odoo/tools/translate.py | 31 +++++------ odoo/tools/yaml_import.py | 19 +++---- 67 files changed, 359 insertions(+), 337 deletions(-) diff --git a/addons/anonymization/models/anonymization.py b/addons/anonymization/models/anonymization.py index 2d4fe1b17d2..a0c90382938 100644 --- a/addons/anonymization/models/anonymization.py +++ b/addons/anonymization/models/anonymization.py @@ -6,6 +6,7 @@ from operator import itemgetter from odoo import api, fields, models, _ from odoo.exceptions import UserError +from odoo.tools import pycompat FIELD_STATES = [('clear', 'Clear'), ('anonymized', 'Anonymized'), ('not_existing', 'Not Existing'), ('new', 'New')] ANONYMIZATION_HISTORY_STATE = [('started', 'Started'), ('done', 'Done'), ('in_exception', 'Exception occured')] @@ -13,7 +14,7 @@ ANONYMIZATION_DIRECTION = [('clear -> anonymized', 'clear -> anonymized'), ('ano def group(lst, cols): - if isinstance(cols, basestring): + if isinstance(cols, pycompat.string_types): cols = [cols] return dict((k, [v for v in itr]) for k, itr in groupby(sorted(lst, key=itemgetter(*cols)), itemgetter(*cols))) diff --git a/addons/base_import/models/base_import.py b/addons/base_import/models/base_import.py index e707beecc17..f2bab8b52b3 100644 --- a/addons/base_import/models/base_import.py +++ b/addons/base_import/models/base_import.py @@ -208,9 +208,9 @@ class Import(models.TransientModel): if cell.ctype is xlrd.XL_CELL_NUMBER: is_float = cell.value % 1 != 0.0 values.append( - unicode(cell.value) + pycompat.text_type(cell.value) if is_float - else unicode(int(cell.value)) + else pycompat.text_type(int(cell.value)) ) elif cell.ctype is xlrd.XL_CELL_DATE: is_datetime = cell.value % 1 != 0.0 @@ -653,7 +653,7 @@ class Import(models.TransientModel): except ValueError as error: return [{ 'type': 'error', - 'message': unicode(error), + 'message': pycompat.text_type(error), 'record': False, }] diff --git a/addons/board/models/board.py b/addons/board/models/board.py index 3acd277826a..81e849af263 100644 --- a/addons/board/models/board.py +++ b/addons/board/models/board.py @@ -2,6 +2,7 @@ # 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): @@ -45,7 +46,7 @@ class Board(models.AbstractModel): return node def encode(s): - if isinstance(s, unicode): + if isinstance(s, pycompat.text_type): return s.encode('utf8') return s diff --git a/addons/bus/controllers/main.py b/addons/bus/controllers/main.py index 40118764751..4e82116e7c7 100644 --- a/addons/bus/controllers/main.py +++ b/addons/bus/controllers/main.py @@ -4,6 +4,8 @@ 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: @@ -14,7 +16,7 @@ class BusController(Controller): @route('/longpolling/send', type="json", auth="public") def send(self, channel, message): - if not isinstance(channel, basestring): + if not isinstance(channel, pycompat.string_types): raise Exception("bus.Bus only string channels are allowed.") return request.env['bus.bus'].sendone(channel, message) @@ -33,7 +35,7 @@ class BusController(Controller): options = {} if not dispatch: raise Exception("bus.Bus unavailable") - if [c for c in channels if not isinstance(c, basestring)]: + if [c for c in channels if not isinstance(c, pycompat.string_types)]: 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/calendar/models/calendar.py b/addons/calendar/models/calendar.py index b0c16c15b5a..a6656af1a5b 100644 --- a/addons/calendar/models/calendar.py +++ b/addons/calendar/models/calendar.py @@ -34,7 +34,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, (basestring)): + if calendar_id and isinstance(calendar_id, pycompat.string_types): res = [bit for bit in calendar_id.split('-') if bit] if len(res) == 2: real_id = res[0] @@ -48,7 +48,7 @@ def calendar_id2real_id(calendar_id=None, with_date=False): def get_real_ids(ids): - if isinstance(ids, (basestring, pycompat.integer_types)): + if isinstance(ids, (pycompat.string_types, pycompat.integer_types)): return calendar_id2real_id(ids) if isinstance(ids, (list, tuple)): @@ -1060,7 +1060,7 @@ class Meeting(models.Model): pile.reverse() new_pile = [] for item in pile: - if not isinstance(item, basestring): + if not isinstance(item, pycompat.string_types): res = item elif str(item) == str('&'): first = new_pile.pop() @@ -1209,7 +1209,7 @@ class Meeting(models.Model): if interval == 'day': # Day number (1-31) - result = unicode(date.day) + result = pycompat.text_type(date.day) elif interval == 'month': # Localized month name and year @@ -1221,6 +1221,7 @@ class Meeting(models.Model): elif interval == 'time': # Localized time + # FIXME: formats are specifically encoded to bytes, maybe use babel? dummy, format_time = self._get_date_formats() result = tools.ustr(date.strftime(format_time + " %Z")) @@ -1316,7 +1317,7 @@ class Meeting(models.Model): @api.returns('self', lambda value: value.id) def message_post(self, **kwargs): thread_id = self.id - if isinstance(self.id, basestring): + if isinstance(self.id, pycompat.string_types): thread_id = get_real_ids(self.id) if self.env.context.get('default_date'): context = dict(self.env.context) @@ -1352,7 +1353,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, basestring): + if isinstance(calendar_id, pycompat.string_types): 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) @@ -1390,7 +1391,7 @@ class Meeting(models.Model): # set end_date for calendar searching if any(field in values for field in ['recurrency', 'end_type', 'count', 'rrule_type', 'start', 'stop']): for real_meeting in real_meetings: - if real_meeting.recurrency and real_meeting.end_type in ('count', unicode('count')): + if real_meeting.recurrency and real_meeting.end_type == u'count': final_date = real_meeting._get_recurrency_end_date() super(Meeting, real_meeting).write({'final_date': final_date}) @@ -1474,7 +1475,7 @@ class Meeting(models.Model): for calendar_id, real_id in select: 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, (basestring, pycompat.integer_types)) and len(ls) >= 2: + if not isinstance(ls, (pycompat.string_types, pycompat.integer_types)) 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 c98242db7e7..ae734ec59f4 100644 --- a/addons/calendar/models/ir_attachment.py +++ b/addons/calendar/models/ir_attachment.py @@ -5,6 +5,8 @@ from odoo import api, models from odoo.addons.calendar.models.calendar import get_real_ids +from odoo.tools import pycompat + class Attachment(models.Model): @@ -16,13 +18,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], basestring): + if args[index][0] == "res_id" and isinstance(args[index][2], pycompat.string_types): 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) @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'), basestring): + if isinstance(vals.get('res_id'), pycompat.string_types): 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 0dc4d24e364..26be5080ab5 100644 --- a/addons/calendar/models/mail_message.py +++ b/addons/calendar/models/mail_message.py @@ -5,6 +5,8 @@ from odoo import api, models from odoo.addons.calendar.models.calendar import get_real_ids +from odoo.tools import pycompat + class Message(models.Model): @@ -16,7 +18,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], basestring): + if isinstance(args[index][2], pycompat.string_types): 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/crm/wizard/base_partner_merge.py b/addons/crm/wizard/base_partner_merge.py index 7751e0106ed..24a573ad871 100644 --- a/addons/crm/wizard/base_partner_merge.py +++ b/addons/crm/wizard/base_partner_merge.py @@ -39,7 +39,7 @@ def html_entity_decode(string): def sanitize_email(email): - assert isinstance(email, basestring) and email + assert isinstance(email, pycompat.string_types) and email result = re.subn(r';|/|:', ',', html_entity_decode(email or ''))[0].split(',') diff --git a/addons/document/models/ir_attachment.py b/addons/document/models/ir_attachment.py index eff40db5df4..7e1afe36e4e 100644 --- a/addons/document/models/ir_attachment.py +++ b/addons/document/models/ir_attachment.py @@ -11,19 +11,6 @@ from odoo import api, models _logger = logging.getLogger(__name__) FTYPES = ['docx', 'pptx', 'xlsx', 'opendoc', 'pdf'] -# Keep function in case it is necessary to do toUnicode(buf.encode('ascii', 'replace')) -def toUnicode(s): - try: - return s.decode('utf-8') - except UnicodeError: - try: - return s.decode('latin') - except UnicodeError: - try: - return s.encode('ascii') - except UnicodeError: - return s - def textToString(element): buff = u"" for node in element.childNodes: diff --git a/addons/hw_escpos/escpos/escpos.py b/addons/hw_escpos/escpos/escpos.py index e50537e0eeb..f076778ca9c 100644 --- a/addons/hw_escpos/escpos/escpos.py +++ b/addons/hw_escpos/escpos/escpos.py @@ -12,6 +12,8 @@ from hashlib import md5 from PIL import Image from xml.etree import ElementTree as ET +from odoo.tools import pycompat + try: import jcconv except ImportError: @@ -27,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,basestring): + if isinstance(stuff,pycompat.string_types): return stuff else: return str(stuff) diff --git a/addons/l10n_be_intrastat/wizard/xml_decl.py b/addons/l10n_be_intrastat/wizard/xml_decl.py index f7d01db30d1..b5486d963c9 100644 --- a/addons/l10n_be_intrastat/wizard/xml_decl.py +++ b/addons/l10n_be_intrastat/wizard/xml_decl.py @@ -6,6 +6,7 @@ from xml.etree import ElementTree as ET from collections import namedtuple from odoo import api, exceptions, fields, models, _ +from odoo.tools.pycompat import text_type INTRASTAT_XMLNS = 'http://www.onegate.eu/2010-01-01' @@ -264,18 +265,18 @@ class XmlDeclaration(models.TransientModel): continue numlgn += 1 item = ET.SubElement(datas, 'Item') - self._set_Dim(item, 'EXSEQCODE', unicode(numlgn)) - self._set_Dim(item, 'EXTRF', unicode(linekey.EXTRF)) - self._set_Dim(item, 'EXCNT', unicode(linekey.EXCNT)) - self._set_Dim(item, 'EXTTA', unicode(linekey.EXTTA)) - self._set_Dim(item, 'EXREG', unicode(linekey.EXREG)) - self._set_Dim(item, 'EXTGO', unicode(linekey.EXGO)) + self._set_Dim(item, 'EXSEQCODE', text_type(numlgn)) + self._set_Dim(item, 'EXTRF', text_type(linekey.EXTRF)) + self._set_Dim(item, 'EXCNT', text_type(linekey.EXCNT)) + self._set_Dim(item, 'EXTTA', text_type(linekey.EXTTA)) + self._set_Dim(item, 'EXREG', text_type(linekey.EXREG)) + self._set_Dim(item, 'EXTGO', text_type(linekey.EXGO)) if extendedmode: - self._set_Dim(item, 'EXTPC', unicode(linekey.EXTPC)) - self._set_Dim(item, 'EXDELTRM', unicode(linekey.EXDELTRM)) - self._set_Dim(item, 'EXTXVAL', unicode(round(amounts[0], 0)).replace(".", ",")) - self._set_Dim(item, 'EXWEIGHT', unicode(round(amounts[1], 0)).replace(".", ",")) - self._set_Dim(item, 'EXUNITS', unicode(round(amounts[2], 0)).replace(".", ",")) + self._set_Dim(item, 'EXTPC', text_type(linekey.EXTPC)) + self._set_Dim(item, 'EXDELTRM', text_type(linekey.EXDELTRM)) + self._set_Dim(item, 'EXTXVAL', text_type(round(amounts[0], 0)).replace(".", ",")) + self._set_Dim(item, 'EXWEIGHT', text_type(round(amounts[1], 0)).replace(".", ",")) + self._set_Dim(item, 'EXUNITS', text_type(round(amounts[2], 0)).replace(".", ",")) if numlgn == 0: #no datas diff --git a/addons/l10n_lu/scripts/tax2csv.py b/addons/l10n_lu/scripts/tax2csv.py index 9993272573f..013df32e3d3 100644 --- a/addons/l10n_lu/scripts/tax2csv.py +++ b/addons/l10n_lu/scripts/tax2csv.py @@ -5,12 +5,11 @@ import xlrd from odoo.tools import pycompat def _e(s): - if type(s) is unicode: - return s.encode('utf8') - elif s is None: + if s is None: return '' - else: - return str(s) + if pycompat.PY2 and type(s) == pycompat.text_type: + return s.encode('utf8') + return str(s) def _is_true(s): diff --git a/addons/mail/controllers/main.py b/addons/mail/controllers/main.py index 74f326d19fb..52ea655c078 100644 --- a/addons/mail/controllers/main.py +++ b/addons/mail/controllers/main.py @@ -13,7 +13,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 +from odoo.tools import consteq, pycompat _logger = logging.getLogger(__name__) @@ -182,7 +182,7 @@ class MailController(http.Controller): else: # either a wrong message_id, either someone trying ids -> just go to messaging return self._redirect_to_messaging() - elif res_id and isinstance(res_id, basestring): + elif res_id and isinstance(res_id, pycompat.string_types): res_id = int(res_id) return self._redirect_to_record(model, res_id, access_token) diff --git a/addons/mail/models/ir_model.py b/addons/mail/models/ir_model.py index e2231e38f5d..01862352e96 100644 --- a/addons/mail/models/ir_model.py +++ b/addons/mail/models/ir_model.py @@ -3,6 +3,7 @@ from odoo import _, api, fields, models from odoo.exceptions import UserError +from odoo.tools import pycompat class IrModel(models.Model): @@ -41,7 +42,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, basestring) else parents + parents = [parents] if isinstance(parents, pycompat.string_types) else parents model_class._inherit = parents + ['mail.thread'] return model_class diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index 35ae6d4ff9e..bc7b1d1072d 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -423,7 +423,7 @@ class MailThread(models.AbstractModel): for field_name, (template, post_kwargs) in pycompat.items(templates): if not template: continue - if isinstance(template, basestring): + if isinstance(template, pycompat.string_types): self.message_post_with_view(template, **post_kwargs) else: self.message_post_with_template(template.id, **post_kwargs) @@ -1268,12 +1268,15 @@ 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) - # FIXME: message_from_string parses from a *native string* - # Warning: message_from_string doesn't always work correctly on unicode, - # we must use utf-8 strings here :-( - if isinstance(message, unicode): + # 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): message = message.encode('utf-8') - msg_txt = email.message_from_string(message) + extract = getattr(email, 'message_from_bytes', email.message_from_string) + msg_txt = extract(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) @@ -1494,9 +1497,9 @@ class MailThread(models.AbstractModel): 'message_type': 'email', } if not isinstance(message, Message): - if isinstance(message, unicode): - # Warning: message_from_string doesn't always work correctly on unicode, - # we must use utf-8 strings here :-( + # message_from_string works on a native str, so on py2 we need to + # encode incoming unicode strings + if pycompat.PY2 and not isinstance(message, str): message = message.encode('utf-8') message = email.message_from_string(message) @@ -1725,11 +1728,11 @@ class MailThread(models.AbstractModel): cid = info and info.get('cid') else: continue - if isinstance(content, unicode): + if isinstance(content, pycompat.text_type): content = content.encode('utf-8') data_attach = { 'name': name, - 'datas': base64.b64encode(str(content)), + 'datas': base64.b64encode(content), 'type': 'binary', 'datas_fname': name, 'description': name, @@ -1922,7 +1925,7 @@ class MailThread(models.AbstractModel): values['slug'] = slug except ImportError: values['slug'] = lambda self: self.id - if isinstance(views_or_xmlid, basestring): + if isinstance(views_or_xmlid, pycompat.string_types): views = self.env.ref(views_or_xmlid, raise_if_not_found=False) else: views = views_or_xmlid diff --git a/addons/payment_authorize/models/authorize_request.py b/addons/payment_authorize/models/authorize_request.py index 0a00b1a4c70..7388a1a4329 100644 --- a/addons/payment_authorize/models/authorize_request.py +++ b/addons/payment_authorize/models/authorize_request.py @@ -58,7 +58,7 @@ class AuthorizeAPI(): :param etree._Element data: etree data to process """ - data = etree.tostring(data, xml_declaration=True, encoding='utf-8') + data = etree.tostring(data, encoding='utf-8') r = requests.post(self.url, data=data, headers={'Content-Type': 'text/xml'}) r.raise_for_status() response = strip_ns(r.content, XMLNS) diff --git a/addons/payment_authorize/tests/test_authorize.py b/addons/payment_authorize/tests/test_authorize.py index b02d3d81209..668e17d0562 100644 --- a/addons/payment_authorize/tests/test_authorize.py +++ b/addons/payment_authorize/tests/test_authorize.py @@ -95,7 +95,7 @@ class AuthorizeForm(AuthorizeCommon): if values[1] in ['submit', 'x_fp_hash', 'return_url', 'x_state', 'x_ship_to_state']: continue self.assertEqual( - unicode(values[2], "utf-8"), + values[2], form_values[values[1]], 'Authorize: wrong value for input %s: received %s instead of %s' % (values[1], values[2], form_values[values[1]]) ) diff --git a/addons/product/models/product.py b/addons/product/models/product.py index 638e898aed8..c550e063709 100644 --- a/addons/product/models/product.py +++ b/addons/product/models/product.py @@ -158,7 +158,7 @@ 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, basestring): + if isinstance(pricelist_id_or_name, pycompat.string_types): 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]]) diff --git a/addons/product/models/product_template.py b/addons/product/models/product_template.py index ccfbcf28b96..c9a2411f173 100644 --- a/addons/product/models/product_template.py +++ b/addons/product/models/product_template.py @@ -171,7 +171,7 @@ 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, basestring): + if isinstance(pricelist_id_or_name, pycompat.string_types): 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]) diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py index 43cbe1e2e4d..693f5c0119e 100644 --- a/addons/stock/models/product.py +++ b/addons/stock/models/product.py @@ -161,7 +161,7 @@ class Product(models.Model): if self.env.context.get('location', False): if isinstance(self.env.context['location'], pycompat.integer_types): location_ids = [self.env.context['location']] - elif isinstance(self.env.context['location'], basestring): + elif isinstance(self.env.context['location'], pycompat.string_types): domain = [('complete_name', 'ilike', self.env.context['location'])] if self.env.context.get('force_company', False): domain += [('company_id', '=', self.env.context['force_company'])] @@ -172,7 +172,7 @@ class Product(models.Model): if self.env.context.get('warehouse', False): if isinstance(self.env.context['warehouse'], pycompat.integer_types): wids = [self.env.context['warehouse']] - elif isinstance(self.env.context['warehouse'], basestring): + elif isinstance(self.env.context['warehouse'], pycompat.string_types): domain = [('name', 'ilike', self.env.context['warehouse'])] if self.env.context.get('force_company', False): domain += [('company_id', '=', self.env.context['force_company'])] diff --git a/addons/survey/controllers/main.py b/addons/survey/controllers/main.py index 553fc5ad4b2..150503f07da 100644 --- a/addons/survey/controllers/main.py +++ b/addons/survey/controllers/main.py @@ -174,7 +174,7 @@ class WebsiteSurvey(http.Controller): answer_tag = "%s_%s" % (answer_tag, 'comment') answer_value = answer.value_text elif answer.answer_type == 'number': - answer_value = answer.value_number.__str__() + answer_value = str(answer.value_number) elif answer.answer_type == 'date': answer_value = answer.value_date elif answer.answer_type == 'suggestion' and not answer.value_suggested_row: diff --git a/addons/survey/wizard/survey_email_compose_message.py b/addons/survey/wizard/survey_email_compose_message.py index fb36d839c57..f23d836bc30 100644 --- a/addons/survey/wizard/survey_email_compose_message.py +++ b/addons/survey/wizard/survey_email_compose_message.py @@ -8,6 +8,7 @@ from werkzeug import urls from odoo import api, fields, models, _ from odoo.exceptions import UserError +from odoo.tools import pycompat emails_split = re.compile(r"[;,\n\r]+") email_validator = re.compile(r"[^@]+@[^@]+\.[^@]+") @@ -119,7 +120,7 @@ class SurveyMailComposeMessage(models.TransientModel): if wizard.public != 'email_private': return None else: - token = uuid.uuid4().__str__() + token = pycompat.text_type(uuid.uuid4()) # create response with token survey_user_input = SurveyUserInput.create({ 'survey_id': wizard.survey_id.id, diff --git a/addons/utm/models/utm.py b/addons/utm/models/utm.py index 5cb04d51425..b73329c1011 100644 --- a/addons/utm/models/utm.py +++ b/addons/utm/models/utm.py @@ -3,6 +3,7 @@ from odoo import api, fields, models, SUPERUSER_ID from odoo.http import request +from odoo.tools import pycompat class UtmMedium(models.Model): @@ -72,7 +73,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, basestring) and value: + if field.type == 'many2one' and isinstance(value, pycompat.string_types) 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 4efc3df9eec..9ac7b7a2fd8 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1396,7 +1396,7 @@ class CSVExport(ExportFormat, http.Controller): for data in rows: row = [] for d in data: - if isinstance(d, unicode): + if type(d) != str and isinstance(d, pycompat.string_types): try: d = d.encode('utf-8') except UnicodeError: @@ -1446,7 +1446,7 @@ class ExcelExport(ExportFormat, http.Controller): for row_index, row in enumerate(rows): for cell_index, cell_value in enumerate(row): cell_style = base_style - if isinstance(cell_value, basestring): + if isinstance(cell_value, pycompat.string_types): cell_value = re.sub("\r", " ", cell_value) elif isinstance(cell_value, datetime.datetime): cell_style = datetime_style diff --git a/addons/web_editor/controllers/main.py b/addons/web_editor/controllers/main.py index c501ce769d2..50a9540323a 100644 --- a/addons/web_editor/controllers/main.py +++ b/addons/web_editor/controllers/main.py @@ -39,7 +39,7 @@ class Web_Editor(http.Controller): debug=request.debug) for k in kwargs: - if isinstance(kwargs[k], basestring) and kwargs[k].isdigit(): + if isinstance(kwargs[k], pycompat.string_types) and kwargs[k].isdigit(): kwargs[k] = int(kwargs[k]) trans = dict( @@ -186,7 +186,7 @@ class Web_Editor(http.Controller): uploads += attachments.read(['name', 'mimetype', 'checksum', 'url']) except Exception as e: logger.exception("Failed to upload image to attachment") - message = unicode(e) + message = pycompat.text_type(e) return """