[FIX] builtins removed from Python 3
* Reverse wrapper courtesy of @rco-odoo's original P3 branch * thin compat module stripped down from werkzeug (to augment as needed) issue 8530
This commit is contained in:
@@ -5,7 +5,7 @@ import math
|
||||
|
||||
from odoo.osv import expression
|
||||
from odoo.tools.float_utils import float_round as round
|
||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, pycompat
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo import api, fields, models, _
|
||||
|
||||
@@ -383,7 +383,7 @@ class AccountJournal(models.Model):
|
||||
account_code_prefix = company.bank_account_code_prefix or ''
|
||||
else:
|
||||
account_code_prefix = company.cash_account_code_prefix or company.bank_account_code_prefix or ''
|
||||
for num in xrange(1, 100):
|
||||
for num in pycompat.range(1, 100):
|
||||
new_code = str(account_code_prefix.ljust(code_digits - 1, '0')) + str(num)
|
||||
rec = self.env['account.account'].search([('code', '=', new_code), ('company_id', '=', company.id)], limit=1)
|
||||
if not rec:
|
||||
@@ -412,7 +412,7 @@ class AccountJournal(models.Model):
|
||||
if not vals.get('code'):
|
||||
journal_code_base = (vals['type'] == 'cash' and 'CSH' or 'BNK')
|
||||
journals = self.env['account.journal'].search([('code', 'like', journal_code_base + '%'), ('company_id', '=', company_id)])
|
||||
for num in xrange(1, 100):
|
||||
for num in pycompat.range(1, 100):
|
||||
# journal_code has a maximal size of 5, hence we can enforce the boundary num < 100
|
||||
journal_code = journal_code_base + str(num)
|
||||
if journal_code not in journals.mapped('code'):
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.osv import expression
|
||||
from odoo.tools import float_is_zero
|
||||
from odoo.tools import float_is_zero, pycompat
|
||||
from odoo.tools import float_compare, float_round
|
||||
from odoo.tools.misc import formatLang
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
@@ -874,10 +874,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'], (int, long)):
|
||||
if isinstance(aml_dict['move_line'], pycompat.integer_types):
|
||||
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 aml_dict['tax_ids'] and isinstance(aml_dict['tax_ids'][0], (int, long)):
|
||||
if aml_dict.get('tax_ids') and isinstance(aml_dict['tax_ids'][0], pycompat.integer_types):
|
||||
# Transform the value in the format required for One2many and Many2many fields
|
||||
aml_dict['tax_ids'] = map(lambda id: (4, id, None), aml_dict['tax_ids'])
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ from datetime import datetime, timedelta
|
||||
from urlparse import urljoin
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.tools import pycompat
|
||||
|
||||
|
||||
class SignupError(Exception):
|
||||
@@ -16,7 +17,7 @@ class SignupError(Exception):
|
||||
def random_token():
|
||||
# the token has an entropy of about 120 bits (6 bits/char * 20 chars)
|
||||
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
||||
return ''.join(random.SystemRandom().choice(chars) for i in xrange(20))
|
||||
return ''.join(random.SystemRandom().choice(chars) for _ in pycompat.range(20))
|
||||
|
||||
def now(**kwargs):
|
||||
dt = datetime.now() + timedelta(**kwargs)
|
||||
|
||||
@@ -17,7 +17,7 @@ import uuid
|
||||
from odoo import api, fields, models
|
||||
from odoo import tools
|
||||
from odoo.tools.translate import _
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT, pycompat
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ def calendar_id2real_id(calendar_id=None, with_date=False):
|
||||
|
||||
|
||||
def get_real_ids(ids):
|
||||
if isinstance(ids, (basestring, int, long)):
|
||||
if isinstance(ids, (basestring, pycompat.integer_types)):
|
||||
return calendar_id2real_id(ids)
|
||||
|
||||
if isinstance(ids, (list, tuple)):
|
||||
@@ -62,6 +62,15 @@ def is_calendar_id(record_id):
|
||||
return len(str(record_id).split('-')) != 1
|
||||
|
||||
|
||||
SORT_ALIASES = {
|
||||
'start': 'sort_start',
|
||||
'start_date': 'sort_start',
|
||||
'start_datetime': 'sort_start',
|
||||
}
|
||||
def sort_remap(f):
|
||||
return SORT_ALIASES.get(f, f)
|
||||
|
||||
|
||||
class Contacts(models.Model):
|
||||
_name = 'calendar.contacts'
|
||||
|
||||
@@ -1062,23 +1071,17 @@ class Meeting(models.Model):
|
||||
continue
|
||||
result_data.append(meeting.get_search_fields(order_fields, r_date=r_start_date))
|
||||
|
||||
if order_fields:
|
||||
uniq = lambda it: collections.OrderedDict((id(x), x) for x in it).values()
|
||||
|
||||
def comparer(left, right):
|
||||
for fn, mult in comparers:
|
||||
result = cmp(fn(left), fn(right))
|
||||
if result:
|
||||
return mult * result
|
||||
return 0
|
||||
|
||||
sort_params = [key.split()[0] if key[-4:].lower() != 'desc' else '-%s' % key.split()[0] for key in (order or self._order).split(',')]
|
||||
sort_params = uniq([comp if comp not in ['start', 'start_date', 'start_datetime'] else 'sort_start' for comp in sort_params])
|
||||
sort_params = uniq([comp if comp not in ['-start', '-start_date', '-start_datetime'] else '-sort_start' for comp in sort_params])
|
||||
comparers = [((itemgetter(col[1:]), -1) if col[0] == '-' else (itemgetter(col), 1)) for col in sort_params]
|
||||
ids = [r['id'] for r in sorted(result_data, cmp=comparer)]
|
||||
|
||||
return ids
|
||||
# seq of (field, should_reverse)
|
||||
sort_spec = list(tools.unique(
|
||||
(sort_remap(key.split()[0]), key.lower().endswith(' desc'))
|
||||
for key in (order or self._order).split(',')
|
||||
))
|
||||
def key(record):
|
||||
return [
|
||||
tools.Reverse(record[name]) if desc else record[name]
|
||||
for name, desc in sort_spec
|
||||
]
|
||||
return [r['id'] for r in sorted(result_data, key=key)]
|
||||
|
||||
@api.multi
|
||||
def _rrule_serialize(self):
|
||||
@@ -1154,7 +1157,7 @@ class Meeting(models.Model):
|
||||
data['final_date'] = rule._until and rule._until.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
#repeat weekly
|
||||
if rule._byweekday:
|
||||
for i in xrange(0, 7):
|
||||
for i in pycompat.range(0, 7):
|
||||
if i in rule._byweekday:
|
||||
data[day_list[i]] = True
|
||||
data['rrule_type'] = 'weekly'
|
||||
@@ -1466,7 +1469,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, int, long)) and len(ls) >= 2:
|
||||
if not isinstance(ls, (basestring, pycompat.integer_types)) and len(ls) >= 2:
|
||||
res['start'] = ls[1]
|
||||
res['stop'] = ls[2]
|
||||
|
||||
|
||||
@@ -97,3 +97,50 @@ class TestCalendar(TransactionCase):
|
||||
self.assertEqual(calendar_event_sprint_review.month_by, 'day', 'rrule_type should be mothly')
|
||||
self.assertEqual(calendar_event_sprint_review.byday, '1', 'rrule_type should be mothly')
|
||||
self.assertEqual(calendar_event_sprint_review.week_list, 'MO', 'rrule_type should be mothly')
|
||||
|
||||
def test_event_order(self):
|
||||
""" check the ordering of events when searching """
|
||||
def create_event(name, date):
|
||||
return self.CalendarEvent.create({
|
||||
'name': name,
|
||||
'start': date + ' 12:00:00',
|
||||
'stop': date + ' 14:00:00',
|
||||
'duration': 2.0,
|
||||
})
|
||||
foo1 = create_event('foo', '2011-04-01')
|
||||
foo2 = create_event('foo', '2011-06-01')
|
||||
bar1 = create_event('bar', '2011-05-01')
|
||||
bar2 = create_event('bar', '2011-06-01')
|
||||
domain = [('id', 'in', (foo1 + foo2 + bar1 + bar2).ids)]
|
||||
|
||||
# sort them by name only
|
||||
events = self.CalendarEvent.search(domain, order='name')
|
||||
self.assertEqual(events.mapped('name'), ['bar', 'bar', 'foo', 'foo'])
|
||||
events = self.CalendarEvent.search(domain, order='name desc')
|
||||
self.assertEqual(events.mapped('name'), ['foo', 'foo', 'bar', 'bar'])
|
||||
|
||||
# sort them by start date only
|
||||
events = self.CalendarEvent.search(domain, order='start')
|
||||
self.assertEqual(events.mapped('start'), (foo1 + bar1 + foo2 + bar2).mapped('start'))
|
||||
events = self.CalendarEvent.search(domain, order='start desc')
|
||||
self.assertEqual(events.mapped('start'), (foo2 + bar2 + bar1 + foo1).mapped('start'))
|
||||
|
||||
# sort them by name then start date
|
||||
events = self.CalendarEvent.search(domain, order='name asc, start asc')
|
||||
self.assertEqual(list(events), [bar1, bar2, foo1, foo2])
|
||||
events = self.CalendarEvent.search(domain, order='name asc, start desc')
|
||||
self.assertEqual(list(events), [bar2, bar1, foo2, foo1])
|
||||
events = self.CalendarEvent.search(domain, order='name desc, start asc')
|
||||
self.assertEqual(list(events), [foo1, foo2, bar1, bar2])
|
||||
events = self.CalendarEvent.search(domain, order='name desc, start desc')
|
||||
self.assertEqual(list(events), [foo2, foo1, bar2, bar1])
|
||||
|
||||
# sort them by start date then name
|
||||
events = self.CalendarEvent.search(domain, order='start asc, name asc')
|
||||
self.assertEqual(list(events), [foo1, bar1, bar2, foo2])
|
||||
events = self.CalendarEvent.search(domain, order='start asc, name desc')
|
||||
self.assertEqual(list(events), [foo1, bar1, foo2, bar2])
|
||||
events = self.CalendarEvent.search(domain, order='start desc, name asc')
|
||||
self.assertEqual(list(events), [bar2, foo2, bar1, foo1])
|
||||
events = self.CalendarEvent.search(domain, order='start desc, name desc')
|
||||
self.assertEqual(list(events), [foo2, bar2, bar1, foo1])
|
||||
|
||||
@@ -7,6 +7,7 @@ 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__)
|
||||
@@ -281,7 +282,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, int, long)):
|
||||
if result is not None and isinstance(result, (float, pycompat.integer_types)):
|
||||
goals_to_write.update(goal._get_write_values(result))
|
||||
else:
|
||||
_logger.error(
|
||||
@@ -322,7 +323,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], (int, long)):
|
||||
if isinstance(queried_value, tuple) and len(queried_value) == 2 and isinstance(queried_value[0], pycompat.integer_types):
|
||||
queried_value = queried_value[0]
|
||||
if queried_value == query_goals[goal.id]:
|
||||
new_value = user_value.get(field_name+'_count', goal.current)
|
||||
|
||||
@@ -74,12 +74,12 @@ class TestPayslipFlow(TestPayslipBase):
|
||||
# I print the payslip report
|
||||
data, format = render_report(self.env.cr, self.env.uid, richard_payslip.ids, 'hr_payroll.report_payslip', {}, {})
|
||||
if config.get('test_report_directory'):
|
||||
file(os.path.join(config['test_report_directory'], 'hr_payroll-payslip.'+ format), 'wb+').write(data)
|
||||
open(os.path.join(config['test_report_directory'], 'hr_payroll-payslip.'+ format), 'wb+').write(data)
|
||||
|
||||
# I print the payslip details report
|
||||
data, format = render_report(self.env.cr, self.env.uid, richard_payslip.ids, 'hr_payroll.report_payslipdetails', {}, {})
|
||||
if config.get('test_report_directory'):
|
||||
file(os.path.join(config['test_report_directory'], 'hr_payroll-payslipdetails.'+ format), 'wb+').write(data)
|
||||
open(os.path.join(config['test_report_directory'], 'hr_payroll-payslipdetails.'+ format), 'wb+').write(data)
|
||||
|
||||
# I print the contribution register report
|
||||
context = {'model': 'hr.contribution.register', 'active_ids': [self.ref('hr_payroll.hr_houserent_register')]}
|
||||
|
||||
@@ -168,8 +168,7 @@ class StyleStack:
|
||||
def to_escpos(self):
|
||||
""" converts the current style to an escpos command string """
|
||||
cmd = ''
|
||||
ordered_cmds = self.cmds.keys()
|
||||
ordered_cmds.sort(lambda x,y: cmp(self.cmds[x]['_order'], self.cmds[y]['_order']))
|
||||
ordered_cmds = sorted(self.cmds.keys(), key=lambda x: self.cmds[x]['_order'])
|
||||
for style in ordered_cmds:
|
||||
cmd += self.cmds[style][self.get(style)]
|
||||
return cmd
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import base64
|
||||
|
||||
from odoo import api, models
|
||||
from odoo.tools import pycompat
|
||||
|
||||
|
||||
class MailTemplate(models.Model):
|
||||
@@ -20,7 +21,7 @@ class MailTemplate(models.Model):
|
||||
rslt = super(MailTemplate, self).generate_email(res_ids, fields)
|
||||
|
||||
multi_mode = True
|
||||
if isinstance(res_ids, (int, long)):
|
||||
if isinstance(res_ids, pycompat.integer_types):
|
||||
res_ids = [res_ids]
|
||||
multi_mode = False
|
||||
|
||||
|
||||
@@ -40,4 +40,4 @@ class TestPaymentAdvice(TestPaymentAdviceBase):
|
||||
# In order to test the PDF report defined on a Payment Advice, we will print a Print Advice Report when NEFT is checked
|
||||
data, format = render_report(self.env.cr, self.env.uid, payment_advice.ids, 'l10n_in_hr_payroll.report_payrolladvice', {}, {})
|
||||
if config.get('test_report_directory'):
|
||||
file(os.path.join(config['test_report_directory'], 'l10n_in_hr_payroll_summary_report' + format), 'wb+').write(data)
|
||||
open(os.path.join(config['test_report_directory'], 'l10n_in_hr_payroll_summary_report' + format), 'wb+').write(data)
|
||||
|
||||
@@ -7,6 +7,8 @@ import copy
|
||||
import datetime
|
||||
import dateutil.relativedelta as relativedelta
|
||||
import logging
|
||||
|
||||
import functools
|
||||
import lxml
|
||||
import urlparse
|
||||
|
||||
@@ -15,6 +17,7 @@ from urllib import urlencode, quote as quote
|
||||
from odoo import _, api, fields, models, tools
|
||||
from odoo import report as odoo_report
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools import pycompat
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -90,10 +93,9 @@ try:
|
||||
'max': max,
|
||||
'sum': sum,
|
||||
'filter': filter,
|
||||
'reduce': reduce,
|
||||
'reduce': functools.reduce,
|
||||
'map': map,
|
||||
'round': round,
|
||||
'cmp': cmp,
|
||||
|
||||
# dateutil.relativedelta is an old-style class and cannot be directly
|
||||
# instanciated wihtin a jinja2 expression, so a lambda "proxy" is
|
||||
@@ -340,7 +342,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, (int, long)):
|
||||
if isinstance(res_ids, pycompat.integer_types):
|
||||
multi_mode = False
|
||||
res_ids = [res_ids]
|
||||
|
||||
@@ -385,7 +387,7 @@ class MailTemplate(models.Model):
|
||||
@api.multi
|
||||
def get_email_template(self, res_ids):
|
||||
multi_mode = True
|
||||
if isinstance(res_ids, (int, long)):
|
||||
if isinstance(res_ids, pycompat.integer_types):
|
||||
res_ids = [res_ids]
|
||||
multi_mode = False
|
||||
|
||||
@@ -450,7 +452,7 @@ class MailTemplate(models.Model):
|
||||
"""
|
||||
self.ensure_one()
|
||||
multi_mode = True
|
||||
if isinstance(res_ids, (int, long)):
|
||||
if isinstance(res_ids, pycompat.integer_types):
|
||||
res_ids = [res_ids]
|
||||
multi_mode = False
|
||||
if fields is None:
|
||||
|
||||
@@ -22,6 +22,7 @@ from lxml import etree
|
||||
from werkzeug import url_encode
|
||||
|
||||
from odoo import _, api, exceptions, fields, models, tools
|
||||
from odoo.tools import pycompat
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
|
||||
|
||||
@@ -1811,7 +1812,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, (int, long)):
|
||||
elif isinstance(partner_id, pycompat.integer_types):
|
||||
partner_ids.add(partner_id)
|
||||
else:
|
||||
pass # we do not manage anything else
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
import logging
|
||||
import threading
|
||||
|
||||
from odoo.tools.misc import split_every
|
||||
|
||||
from odoo import _, api, fields, models, registry, SUPERUSER_ID
|
||||
from odoo.osv import expression
|
||||
|
||||
@@ -107,9 +109,8 @@ class Partner(models.Model):
|
||||
@api.model
|
||||
def _notify_send(self, body, subject, recipients, **mail_values):
|
||||
emails = self.env['mail.mail']
|
||||
recipients_nbr, recipients_max = len(recipients), 50
|
||||
email_chunks = [recipients[x:x + recipients_max] for x in xrange(0, len(recipients), recipients_max)]
|
||||
for email_chunk in email_chunks:
|
||||
recipients_nbr = len(recipients)
|
||||
for email_chunk in split_every(50, recipients.ids):
|
||||
# TDE FIXME: missing message parameter. So we will find mail_message_id
|
||||
# in the mail_values and browse it. It should already be in the
|
||||
# cache so should not impact performances.
|
||||
@@ -117,9 +118,9 @@ class Partner(models.Model):
|
||||
message = self.env['mail.message'].browse(mail_message_id) if mail_message_id else None
|
||||
if message and message.model and message.res_id and message.model in self.env and hasattr(self.env[message.model], 'message_get_recipient_values'):
|
||||
tig = self.env[message.model].browse(message.res_id)
|
||||
recipient_values = tig.message_get_recipient_values(notif_message=message, recipient_ids=email_chunk.ids)
|
||||
recipient_values = tig.message_get_recipient_values(notif_message=message, recipient_ids=email_chunk)
|
||||
else:
|
||||
recipient_values = self.env['mail.thread'].message_get_recipient_values(notif_message=None, recipient_ids=email_chunk.ids)
|
||||
recipient_values = self.env['mail.thread'].message_get_recipient_values(notif_message=None, recipient_ids=email_chunk)
|
||||
create_values = {
|
||||
'body_html': body,
|
||||
'subject': subject,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import _, api, exceptions, fields, models
|
||||
from odoo.tools import pycompat
|
||||
|
||||
|
||||
class Users(models.Model):
|
||||
@@ -97,7 +98,7 @@ class Users(models.Model):
|
||||
current_pids.append(partner_id[1])
|
||||
elif isinstance(partner_id, (list, tuple)) and partner_id[0] == 6 and len(partner_id) == 3:
|
||||
current_pids.append(partner_id[2])
|
||||
elif isinstance(partner_id, (int, long)):
|
||||
elif isinstance(partner_id, pycompat.integer_types):
|
||||
current_pids.append(partner_id)
|
||||
if user_pid not in current_pids:
|
||||
partner_ids.append(user_pid)
|
||||
|
||||
@@ -5,6 +5,7 @@ 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
|
||||
|
||||
|
||||
@@ -434,7 +435,7 @@ class MailComposer(models.TransientModel):
|
||||
"""
|
||||
self.ensure_one()
|
||||
multi_mode = True
|
||||
if isinstance(res_ids, (int, long)):
|
||||
if isinstance(res_ids, pycompat.integer_types):
|
||||
multi_mode = False
|
||||
res_ids = [res_ids]
|
||||
|
||||
@@ -484,7 +485,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, (int, long)):
|
||||
if isinstance(res_ids, pycompat.integer_types):
|
||||
multi_mode = False
|
||||
res_ids = [res_ids]
|
||||
|
||||
|
||||
@@ -344,7 +344,7 @@ class PaymentTxOgone(models.Model):
|
||||
'USERID': account.ogone_userid,
|
||||
'PSWD': account.ogone_password,
|
||||
'ORDERID': reference,
|
||||
'AMOUNT': long(self.amount * 100),
|
||||
'AMOUNT': self.amount * 100,
|
||||
'CURRENCY': self.currency_id.name,
|
||||
'OPERATION': 'SAL',
|
||||
'ECI': 2, # Recurring (from MOTO)
|
||||
|
||||
@@ -9,6 +9,8 @@ from odoo.osv import expression
|
||||
|
||||
import odoo.addons.decimal_precision as dp
|
||||
|
||||
from odoo.tools import pycompat
|
||||
|
||||
|
||||
class ProductCategory(models.Model):
|
||||
_name = "product.category"
|
||||
@@ -184,7 +186,7 @@ class ProductProduct(models.Model):
|
||||
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, (int, long)):
|
||||
elif isinstance(pricelist_id_or_name, pycompat.integer_types):
|
||||
pricelist = self.env['product.pricelist'].browse(pricelist_id_or_name)
|
||||
|
||||
if pricelist:
|
||||
|
||||
@@ -8,6 +8,7 @@ import odoo.addons.decimal_precision as dp
|
||||
|
||||
from odoo import api, fields, models, tools, _
|
||||
from odoo.exceptions import ValidationError, except_orm
|
||||
from odoo.tools import pycompat
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
@@ -164,7 +165,7 @@ class ProductTemplate(models.Model):
|
||||
# Support context pricelists specified as display_name or ID for compatibility
|
||||
if isinstance(pricelist_id_or_name, basestring):
|
||||
pricelist = self.env['product.pricelist'].name_search(pricelist_id_or_name, operator='=', limit=1)
|
||||
elif isinstance(pricelist_id_or_name, (int, long)):
|
||||
elif isinstance(pricelist_id_or_name, pycompat.integer_types):
|
||||
pricelist = self.env['product.pricelist'].browse(pricelist_id_or_name)
|
||||
|
||||
if pricelist:
|
||||
|
||||
@@ -577,7 +577,7 @@ class Report(models.Model):
|
||||
writer = PdfFileWriter()
|
||||
streams = [] # We have to close the streams *after* PdfFilWriter's call to write()
|
||||
for document in documents:
|
||||
pdfreport = file(document, 'rb')
|
||||
pdfreport = open(document, 'rb')
|
||||
streams.append(pdfreport)
|
||||
reader = PdfFileReader(pdfreport)
|
||||
for page in range(0, reader.getNumPages()):
|
||||
|
||||
@@ -31,4 +31,4 @@ class RepoortIntrastatTest(common.TransactionCase):
|
||||
def test_00_create_pdf(self):
|
||||
data, report_format = self.env['ir.actions.report.xml'].render_report(self.invoice.ids, 'report_intrastat.report_intrastatinvoice', {})
|
||||
if tools.config['test_report_directory']:
|
||||
file(os.path.join(tools.config['test_report_directory'], 'report_intrastat-intrastat_report.' + report_format), 'wb+').write(data)
|
||||
open(os.path.join(tools.config['test_report_directory'], 'report_intrastat-intrastat_report.' + report_format), 'wb+').write(data)
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
import babel.dates
|
||||
|
||||
from datetime import datetime, timedelta, date, time
|
||||
|
||||
from dateutil import rrule
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo.fields import Date, Datetime
|
||||
@@ -349,13 +351,7 @@ class TestWorkDays(TestResourceCommon):
|
||||
]
|
||||
})
|
||||
|
||||
self._days = [
|
||||
date.fromordinal(o)
|
||||
for o in xrange(
|
||||
WAR_START.toordinal(),
|
||||
WAR_END.toordinal() + 1
|
||||
)
|
||||
]
|
||||
self._days = [dt.date() for dt in rrule.rrule(rrule.DAILY, dtstart=WAR_START, until=WAR_END)]
|
||||
|
||||
def test_trivial_calendar_no_leaves(self):
|
||||
""" If leaves are not involved, only calendar attendances (basic
|
||||
|
||||
@@ -56,11 +56,11 @@ class AccountInvoice(models.Model):
|
||||
def _refund_cleanup_lines(self, lines):
|
||||
result = super(AccountInvoice, self)._refund_cleanup_lines(lines)
|
||||
if self.env.context.get('mode') == 'modify':
|
||||
for i in xrange(0, len(lines)):
|
||||
for name, field in lines[i]._fields.iteritems():
|
||||
for i, line in enumerate(lines):
|
||||
for name, field in line._fields.iteritems():
|
||||
if name == 'sale_line_ids':
|
||||
result[i][2][name] = [(6, 0, lines[i][name].ids)]
|
||||
lines[i][name] = False
|
||||
result[i][2][name] = [(6, 0, line[name].ids)]
|
||||
line[name] = False
|
||||
return result
|
||||
|
||||
@api.multi
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
from collections import defaultdict
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from odoo.tools.misc import split_every
|
||||
from psycopg2 import OperationalError
|
||||
|
||||
from odoo import api, fields, models, registry, _
|
||||
@@ -239,9 +240,9 @@ class ProcurementOrder(models.Model):
|
||||
|
||||
# Search all confirmed stock_moves and try to assign them
|
||||
confirmed_moves = self.env['stock.move'].search([('state', '=', 'confirmed')], limit=None, order='priority desc, date_expected asc')
|
||||
for x in xrange(0, len(confirmed_moves.ids), 100):
|
||||
for moves_chunk in split_every(100, confirmed_moves.ids):
|
||||
# TDE CLEANME: muf muf
|
||||
self.env['stock.move'].browse(confirmed_moves.ids[x:x + 100]).action_assign()
|
||||
self.env['stock.move'].browse(moves_chunk).action_assign()
|
||||
if use_new_cursor:
|
||||
self._cr.commit()
|
||||
if use_new_cursor:
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.addons import decimal_precision as dp
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools import pycompat
|
||||
from odoo.tools.float_utils import float_round
|
||||
from datetime import datetime
|
||||
import operator as py_operator
|
||||
@@ -180,7 +181,7 @@ class Product(models.Model):
|
||||
|
||||
location_ids = []
|
||||
if self.env.context.get('location', False):
|
||||
if isinstance(self.env.context['location'], (int, long)):
|
||||
if isinstance(self.env.context['location'], pycompat.integer_types):
|
||||
location_ids = [self.env.context['location']]
|
||||
elif isinstance(self.env.context['location'], basestring):
|
||||
domain = [('complete_name', 'ilike', self.env.context['location'])]
|
||||
@@ -191,7 +192,7 @@ class Product(models.Model):
|
||||
location_ids = self.env.context['location']
|
||||
else:
|
||||
if self.env.context.get('warehouse', False):
|
||||
if isinstance(self.env.context['warehouse'], (int, long)):
|
||||
if isinstance(self.env.context['warehouse'], pycompat.integer_types):
|
||||
wids = [self.env.context['warehouse']]
|
||||
elif isinstance(self.env.context['warehouse'], basestring):
|
||||
domain = [('name', 'ilike', self.env.context['warehouse'])]
|
||||
@@ -326,7 +327,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'], (int, long)):
|
||||
if self._context.get('location') and isinstance(self._context['location'], pycompat.integer_types):
|
||||
location = self.env['stock.location'].browse(self._context['location'])
|
||||
fields = res.get('fields')
|
||||
if fields:
|
||||
|
||||
@@ -7,6 +7,7 @@ from lxml import etree, html
|
||||
|
||||
from odoo.exceptions import AccessError
|
||||
from odoo import api, models
|
||||
from odoo.tools import pycompat
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -121,7 +122,7 @@ class IrUiView(models.Model):
|
||||
def _view_obj(self, view_id):
|
||||
if isinstance(view_id, basestring):
|
||||
return self.env.ref(view_id)
|
||||
elif isinstance(view_id, (int, long)):
|
||||
elif isinstance(view_id, pycompat.integer_types):
|
||||
return self.browse(view_id)
|
||||
# assume it's already a view object (WTF?)
|
||||
return view_id
|
||||
|
||||
@@ -10,6 +10,7 @@ from odoo import tools
|
||||
|
||||
from odoo.addons.website.models import website
|
||||
from odoo.http import request
|
||||
from odoo.tools import pycompat
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -63,7 +64,7 @@ class View(models.Model):
|
||||
return views.filter_duplicate()
|
||||
else:
|
||||
return self.env.ref(view_id)
|
||||
elif isinstance(view_id, (int, long)):
|
||||
elif isinstance(view_id, pycompat.integer_types):
|
||||
return self.browse(view_id)
|
||||
|
||||
# assume it's already a view object (WTF?)
|
||||
@@ -72,7 +73,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, (int, long)):
|
||||
if 'website_id' in self._context and not isinstance(xml_id, pycompat.integer_types):
|
||||
domain = [('key', '=', xml_id), '|', ('website_id', '=', self._context['website_id']), ('website_id', '=', False)]
|
||||
view = self.search(domain, order='website_id', limit=1)
|
||||
if not view:
|
||||
|
||||
@@ -19,7 +19,7 @@ except ImportError:
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo import tools
|
||||
from odoo.tools import ustr
|
||||
from odoo.tools import ustr, pycompat
|
||||
from odoo.http import request
|
||||
from odoo.tools.translate import _
|
||||
|
||||
@@ -421,7 +421,7 @@ class Website(models.Model):
|
||||
@api.model
|
||||
def get_template(self, template):
|
||||
View = self.env['ir.ui.view']
|
||||
if isinstance(template, (int, long)):
|
||||
if isinstance(template, pycompat.integer_types):
|
||||
view_id = template
|
||||
else:
|
||||
if '.' not in template:
|
||||
@@ -486,7 +486,7 @@ class Website(models.Model):
|
||||
'num': pmax
|
||||
},
|
||||
"pages": [
|
||||
{'url': get_url(page), 'num': page} for page in xrange(pmin, pmax+1)
|
||||
{'url': get_url(page), 'num': page} for page in pycompat.range(pmin, pmax+1)
|
||||
]
|
||||
}
|
||||
|
||||
@@ -544,8 +544,7 @@ class Website(models.Model):
|
||||
values = [{}]
|
||||
convitems = converters.items()
|
||||
# converters with a domain are processed after the other ones
|
||||
gd = lambda x: hasattr(x[1], 'domain') and (x[1].domain != '[]')
|
||||
convitems.sort(lambda x, y: cmp(gd(x), gd(y)))
|
||||
convitems.sort(key=lambda x: hasattr(x[1], 'domain') and (x[1].domain != '[]'))
|
||||
for (i, (name, converter)) in enumerate(convitems):
|
||||
newval = []
|
||||
for val in values:
|
||||
|
||||
@@ -10,6 +10,8 @@ import lxml.html
|
||||
import odoo
|
||||
import re
|
||||
|
||||
from odoo.tools import pycompat
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -38,7 +40,7 @@ class Crawler(odoo.tests.HttpCase):
|
||||
_logger.info("%s %s", msg, url)
|
||||
r = self.url_open(url)
|
||||
code = r.getcode()
|
||||
self.assertIn(code, xrange(200, 300), "%s Fetching %s returned error response (%d)" % (msg, url, code))
|
||||
self.assertIn(code, pycompat.range(200, 300), "%s Fetching %s returned error response (%d)" % (msg, url, code))
|
||||
|
||||
if r.info().gettype() == 'text/html':
|
||||
doc = lxml.html.fromstring(r.read())
|
||||
|
||||
+132
-17
@@ -16,13 +16,28 @@ with both.
|
||||
Here are a few useful steps or reminders to make Python 2 code compatible
|
||||
with Python 3.
|
||||
|
||||
.. important::
|
||||
|
||||
This is not a general-purpose guide for porting Python 2 to Python 3, it's
|
||||
a guide to write 2/3-compatible Odoo code. It does not go through all the
|
||||
changes in Python but rather through issues which have been found in the
|
||||
standard Odoo distribution in order to show how to evolve such code such
|
||||
that it works on both Python 2 and Python 3.
|
||||
|
||||
References/useful documents:
|
||||
|
||||
* `What's new in Python 3? <https://docs.python.org/3.0/whatsnew/3.0.html>`_
|
||||
covers many of the changes between Python 2 and Python 3, though it is
|
||||
missing a number of changes which `were backported to Python 2.7 <https://docs.python.org/2.7/whatsnew/2.7.html#python-3-1-features>`_
|
||||
as well as :ref:`some feature reintroductions <p3support>` of later Python 3
|
||||
revisions
|
||||
* `How do I port to Python 3? <https://eev.ee/blog/2016/07/31/python-faq-how-do-i-port-to-python-3/>`_
|
||||
* `Python-Future <http://python-future.org/index.html>`_
|
||||
* `Porting Python 2 code to Python 3 <https://docs.python.org/3/howto/pyporting.html>`_
|
||||
* `Porting to Python 3: A Guide <http://lucumr.pocoo.org/2010/2/11/porting-to-python-3-a-guide/>`_ (a bit outdated but useful for the extensive comments on strings and IO)
|
||||
|
||||
.. _p3support:
|
||||
|
||||
Versions Support
|
||||
================
|
||||
|
||||
@@ -37,16 +52,17 @@ features whereas:
|
||||
* Python 3.4 has no specific compatibility improvement but is the lowest P3
|
||||
version for PyLint
|
||||
* Python 3.3 reintroduced the "u" prefix for proper (unicode) strings
|
||||
* Python 3.2 made ``range`` views more list-like and reintroduced ``callable``
|
||||
* Python 3.2 made ``range`` views more list-like (backported to 2.7)and
|
||||
reintroduced ``callable``
|
||||
|
||||
.. warning::
|
||||
|
||||
Python 3 adds plenty of great features (keyword-only parameters,
|
||||
generator delegation, pathlib, ...), do not use them until Python 2
|
||||
support is dropped
|
||||
While Python 3 adds plenty of great features (keyword-only parameters,
|
||||
generator delegation, pathlib, ...), you must *not *use them in Odoo
|
||||
until Python 2 support is dropped
|
||||
|
||||
Fixes
|
||||
=====
|
||||
Moved and removed
|
||||
=================
|
||||
|
||||
Exception Handlers
|
||||
------------------
|
||||
@@ -87,33 +103,132 @@ or::
|
||||
This form was implemented in Python 2.5 and is thus compatible across the
|
||||
board.
|
||||
|
||||
Removed Operators
|
||||
-----------------
|
||||
Operators & keywords
|
||||
--------------------
|
||||
|
||||
.. important::
|
||||
.. important:: The backtick operator ```foo``` must be converted to an
|
||||
explicit call to the ``repr()`` builtin
|
||||
|
||||
* The backtick operator ``\`foo\``` must be converted to an explicit call
|
||||
to the ``repr()`` builtin
|
||||
* The ``<>`` operator must be replaced by ``!=``
|
||||
.. important:: The ``<>`` operator must be replaced by ``!=``
|
||||
|
||||
These two operators were long recommended against/deprecated in Python 2,
|
||||
Python 3 removed them from the language.
|
||||
|
||||
Removed/renamed builtins
|
||||
------------------------
|
||||
.. _changed-exec:
|
||||
|
||||
.. important:: ``exec`` is now a builtin
|
||||
|
||||
In Python 2, ``exec`` is a statement/keyword. Much like ``print``, it's been
|
||||
converted to a builtin function in Python 3. However because the Python 2
|
||||
version can take a tuple parameter it is easy to convert the odd ``exec``
|
||||
statement to the following cross-language forms::
|
||||
|
||||
exec(source)
|
||||
exec(source, globals)
|
||||
exec(source, globals, locals)
|
||||
|
||||
builtins
|
||||
--------
|
||||
|
||||
``cmp``
|
||||
#######
|
||||
|
||||
The ``cmp`` builtin function has been removed from Python 3.
|
||||
|
||||
* Most of its uses are in ``cmp=`` parameters to sort functions where it can
|
||||
usually be replaced by a key function.
|
||||
* Other uses found were obtaining the sign of an item (``cmp(item, 0)``), this
|
||||
can be replicated using the standard library's ``math.copysign`` e.g.
|
||||
``math.copysign(1, item)`` will return ``1.0`` if ``item`` is positive and
|
||||
``-1.0`` if ``item`` is negative.
|
||||
|
||||
``execfile``
|
||||
############
|
||||
|
||||
``execfile(path)`` has been removed completely from Python 3 but it is
|
||||
trivially replaceable in all cases by::
|
||||
|
||||
exec(open(path, 'rb').open())
|
||||
|
||||
of a variant thereof (see :ref:`exec changes <changed-exec>` for details)
|
||||
|
||||
``file``
|
||||
########
|
||||
|
||||
The ``file`` builtin has been removed in Python 3. Generally, it can just
|
||||
be replaced by the ``open`` builtin, although you may want to use ``io.open``
|
||||
which is more flexible and better handles the binary/text dichotomy,
|
||||
:ref:`a big issue in cross-version Python <changed-strings>`.
|
||||
|
||||
.. note::
|
||||
|
||||
In Python 3, the ``open`` builtin is actually an alias for ``io.open``.
|
||||
|
||||
``long``
|
||||
########
|
||||
|
||||
In Python 2, integers can be either ``int`` or ``long``. Python 3 unifies this
|
||||
under the single ``int`` type.
|
||||
|
||||
.. important::
|
||||
|
||||
* 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
|
||||
Python 2 as "overflowing" integer literals will implicitly instantiate long.
|
||||
* in Python 2, a call to ``int()`` will implicitly create a ``long`` object if
|
||||
necessary.
|
||||
* type-testing is the last and bigger issue as in Python 2 ``long`` is not a
|
||||
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``
|
||||
##########
|
||||
|
||||
In Python 3, ``reduce`` has been demoted from builtin to ``functools.reduce``.
|
||||
However this is because many (if not most) uses of ``reduce`` can be replaced
|
||||
by ``sum``, ``all``, ``any`` or a list comprehension for a more readable and
|
||||
faster result.
|
||||
However this is because *most uses of ``reduce`` can be replaced by ``sum``,
|
||||
``all``, ``any``* or a list comprehension for a more readable and faster
|
||||
result.
|
||||
|
||||
It is easy enough to just add ``from functools import reduce`` to the file
|
||||
and compatible with Python 2.6 and later, but consider whether you get better
|
||||
code by replacing it with some other method altogether.
|
||||
|
||||
``xrange``
|
||||
##########
|
||||
|
||||
In Python 3, ``range()`` behaves the same as Python 3's ``xrange``. For
|
||||
cross-versions code you can:
|
||||
|
||||
* just use ``range()`` everywhere and ignore the allocation cost of a list in
|
||||
Python 2 (often not an issue)
|
||||
* conditionally alias ``xrange`` to ``range`` in Python 3 and use that
|
||||
* use a combination of ``itertools.count`` and ``takewhile`` for a
|
||||
cross-compatible lazy increasing sequence of numbers
|
||||
|
||||
.. warning::
|
||||
|
||||
In the *rare* cases where you need conditional code (code which applies
|
||||
for one version of python and not the other), use ``sys.version_info``
|
||||
e.g. ``sys.version_info() >= (3,)`` for Python3+ code or
|
||||
``sys.version_info() < (3,)`` for Python 2 code.
|
||||
|
||||
Removed/renamed methods
|
||||
-----------------------
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ from odoo import api, fields, models, SUPERUSER_ID, tools, _
|
||||
from odoo.exceptions import AccessError, UserError, ValidationError
|
||||
from odoo.modules.registry import Registry
|
||||
from odoo.osv import expression
|
||||
from odoo.tools import pycompat
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
@@ -1055,7 +1056,7 @@ class IrModelAccess(models.Model):
|
||||
else:
|
||||
model_name = model
|
||||
|
||||
if isinstance(group_ids, (int, long)):
|
||||
if isinstance(group_ids, pycompat.integer_types):
|
||||
group_ids = [group_ids]
|
||||
|
||||
query = """ SELECT 1 FROM ir_model_access a
|
||||
|
||||
@@ -4,6 +4,7 @@ import ast
|
||||
from urlparse import urlparse
|
||||
from lxml import html
|
||||
|
||||
from odoo.tools import pycompat
|
||||
from .qweb import QWeb, Contextifier
|
||||
from .assetsbundle import AssetsBundle
|
||||
from lxml import etree
|
||||
@@ -90,7 +91,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, (int, long)) or is_child_view(name):
|
||||
if isinstance(name, pycompat.integer_types) or is_child_view(name):
|
||||
for node in etree.fromstring(template):
|
||||
if node.get('t-name'):
|
||||
node.set('t-name', str(name))
|
||||
|
||||
@@ -11,6 +11,9 @@ from werkzeug.utils import escape as _escape
|
||||
from itertools import chain, izip, tee
|
||||
import __builtin__
|
||||
from functools import reduce
|
||||
|
||||
from odoo.tools import pycompat
|
||||
|
||||
builtin_defaults = {name: getattr(__builtin__, name) for name in dir(__builtin__)}
|
||||
|
||||
try:
|
||||
@@ -160,7 +163,7 @@ def foreach_iterator(base_ctx, enum, name):
|
||||
if not enum:
|
||||
return
|
||||
if isinstance(enum, int):
|
||||
enum = xrange(enum)
|
||||
enum = pycompat.range(enum)
|
||||
size = None
|
||||
if isinstance(enum, Sized):
|
||||
ctx["%s_size" % name] = size = len(enum)
|
||||
|
||||
@@ -8,6 +8,7 @@ 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__)
|
||||
|
||||
@@ -395,7 +396,7 @@ class IrTranslation(models.Model):
|
||||
if isinstance(types, basestring):
|
||||
types = (types,)
|
||||
if res_id:
|
||||
if isinstance(res_id, (int, long)):
|
||||
if isinstance(res_id, pycompat.integer_types):
|
||||
res_id = (res_id,)
|
||||
else:
|
||||
res_id = tuple(res_id)
|
||||
|
||||
@@ -133,9 +133,9 @@ class IrUiMenu(models.Model):
|
||||
if not self._context.get('ir.ui.menu.full_list'):
|
||||
menus = menus._filter_visible_menus()
|
||||
if offset:
|
||||
menus = menus[long(offset):]
|
||||
menus = menus[offset:]
|
||||
if limit:
|
||||
menus = menus[:long(limit)]
|
||||
menus = menus[:limit]
|
||||
return len(menus) if count else menus
|
||||
|
||||
@api.multi
|
||||
|
||||
@@ -22,7 +22,7 @@ from odoo.exceptions import ValidationError
|
||||
from odoo.http import request
|
||||
from odoo.modules.module import get_resource_from_path, get_resource_path
|
||||
from odoo.osv import orm
|
||||
from odoo.tools import config, graph, ConstantMapping, SKIPPED_ELEMENT_TYPES
|
||||
from odoo.tools import config, graph, ConstantMapping, SKIPPED_ELEMENT_TYPES, pycompat
|
||||
from odoo.tools.convert import _fix_multiple_roots
|
||||
from odoo.tools.parse_version import parse_version
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
@@ -944,7 +944,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, (int, long)):
|
||||
if isinstance(template, pycompat.integer_types):
|
||||
return template
|
||||
if '.' not in template:
|
||||
raise ValueError('Invalid template id: %r' % template)
|
||||
@@ -1045,7 +1045,7 @@ actual arch.
|
||||
|
||||
@api.multi
|
||||
def render(self, values=None, engine='ir.qweb'):
|
||||
assert isinstance(self.id, (int, long))
|
||||
assert isinstance(self.id, pycompat.integer_types)
|
||||
|
||||
qcontext = dict(
|
||||
env=self.env,
|
||||
|
||||
@@ -5,6 +5,7 @@ from operator import itemgetter
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools import pycompat
|
||||
|
||||
TYPE2FIELD = {
|
||||
'char': 'value_text',
|
||||
@@ -70,7 +71,7 @@ class Property(models.Model):
|
||||
if field == 'value_reference':
|
||||
if isinstance(value, models.BaseModel):
|
||||
value = '%s,%d' % (value._name, value.id)
|
||||
elif isinstance(value, (int, long)):
|
||||
elif isinstance(value, pycompat.integer_types):
|
||||
field_id = values.get('fields_id')
|
||||
if not field_id:
|
||||
if not prop:
|
||||
|
||||
@@ -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
|
||||
from odoo.tools import mute_logger, pycompat
|
||||
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, (int, long))
|
||||
self.assertIsInstance(count2, (int, long))
|
||||
self.assertIsInstance(count1, pycompat.integer_types)
|
||||
self.assertIsInstance(count2, pycompat.integer_types)
|
||||
self.assertEqual(count1, count2)
|
||||
|
||||
@mute_logger('odoo.models')
|
||||
|
||||
@@ -214,9 +214,8 @@ class TestExpression(TransactionCase):
|
||||
|
||||
# create new company with partners, and partners with no company
|
||||
company2 = self.env['res.company'].create({'name': 'Acme 2'})
|
||||
for i in xrange(4):
|
||||
for i in range(4):
|
||||
Partner.create({'name': 'P of Acme %s' % i, 'company_id': company2.id})
|
||||
for i in xrange(4):
|
||||
Partner.create({'name': 'P of All %s' % i, 'company_id': False})
|
||||
|
||||
# check if many2one works with negative empty list
|
||||
|
||||
@@ -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
|
||||
from odoo.tools import float_compare, float_is_zero, float_repr, float_round, float_split_str, pycompat
|
||||
|
||||
|
||||
class TestFloatPrecision(TransactionCase):
|
||||
@@ -98,14 +98,13 @@ class TestFloatPrecision(TransactionCase):
|
||||
precisions = [2, 2, 2, 2, 2, 2, 3, 4]
|
||||
# Note: max precision for double floats is 53 bits of precision or
|
||||
# 17 significant decimal digits
|
||||
for magnitude in range(7):
|
||||
for i in xrange(len(fractions)):
|
||||
frac, exp, prec = fractions[i], expecteds[i], precisions[i]
|
||||
for magnitude in pycompat.range(7):
|
||||
for frac, exp, prec in zip(fractions, expecteds, precisions):
|
||||
for sign in [-1,1]:
|
||||
for x in xrange(0,10000,97):
|
||||
n = x * 10**magnitude
|
||||
for x in pycompat.range(0, 10000, 97):
|
||||
n = x * 10 ** magnitude
|
||||
f = sign * (n + frac)
|
||||
f_exp = ('-' if f != 0 and sign == -1 else '') + str(n) + exp
|
||||
f_exp = ('-' if f != 0 and sign == -1 else '') + str(n) + exp
|
||||
try_round(f, f_exp, digits=prec)
|
||||
|
||||
def try_zero(amount, expected):
|
||||
|
||||
@@ -154,7 +154,7 @@ class TestIrSequenceGenerate(unittest.TestCase):
|
||||
self.assertTrue(seq)
|
||||
|
||||
with environment() as env:
|
||||
for i in xrange(1, 10):
|
||||
for i in range(1, 10):
|
||||
n = env['ir.sequence'].next_by_code('test_sequence_type_5')
|
||||
self.assertEqual(n, str(i))
|
||||
|
||||
@@ -169,7 +169,7 @@ class TestIrSequenceGenerate(unittest.TestCase):
|
||||
self.assertTrue(seq)
|
||||
|
||||
with environment() as env:
|
||||
for i in xrange(1, 10):
|
||||
for i in range(1, 10):
|
||||
n = env['ir.sequence'].next_by_code('test_sequence_type_6')
|
||||
self.assertEqual(n, str(i))
|
||||
|
||||
|
||||
@@ -116,16 +116,16 @@ class TestIrSequenceDateRangeChangeImplementation(SingleTransactionCase):
|
||||
seq = self.env['ir.sequence']
|
||||
seq16 = self.env['ir.sequence'].with_context({'ir_sequence_date': january(16)})
|
||||
|
||||
for i in xrange(1, 5):
|
||||
for i in range(1, 5):
|
||||
n = seq.next_by_code('test_sequence_date_range_3')
|
||||
self.assertEqual(n, str(i))
|
||||
for i in xrange(1, 5):
|
||||
for i in range(1, 5):
|
||||
n = seq16.next_by_code('test_sequence_date_range_3')
|
||||
self.assertEqual(n, str(i))
|
||||
for i in xrange(1, 5):
|
||||
for i in range(1, 5):
|
||||
n = seq.next_by_code('test_sequence_date_range_4')
|
||||
self.assertEqual(n, str(i))
|
||||
for i in xrange(1, 5):
|
||||
for i in range(1, 5):
|
||||
n = seq16.next_by_code('test_sequence_date_range_4')
|
||||
self.assertEqual(n, str(i))
|
||||
|
||||
|
||||
@@ -16,14 +16,14 @@ class TestCountingStream(unittest.TestCase):
|
||||
self.assertEqual(s.index, 0)
|
||||
|
||||
def test_single(self):
|
||||
s = misc.CountingStream(xrange(1))
|
||||
s = misc.CountingStream(range(1))
|
||||
self.assertEqual(s.index, -1)
|
||||
self.assertEqual(next(s, None), 0)
|
||||
self.assertIsNone(next(s, None))
|
||||
self.assertEqual(s.index, 1)
|
||||
|
||||
def test_full(self):
|
||||
s = misc.CountingStream(xrange(42))
|
||||
s = misc.CountingStream(range(42))
|
||||
for _ in s:
|
||||
pass
|
||||
self.assertEqual(s.index, 42)
|
||||
|
||||
@@ -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
|
||||
from odoo.tools import mute_logger, pycompat
|
||||
|
||||
|
||||
class TestORM(TransactionCase):
|
||||
@@ -193,7 +193,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, int, long))
|
||||
self.assertIsInstance(defaults['partner_id'], (bool, pycompat.integer_types))
|
||||
|
||||
def test_create(self):
|
||||
""" creating a user should automatically create a new partner """
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
from odoo import exceptions
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.tools import pycompat
|
||||
|
||||
|
||||
class TestResConfig(TransactionCase):
|
||||
@@ -42,7 +43,7 @@ class TestResConfig(TransactionCase):
|
||||
self.assertIsInstance(res, tuple)
|
||||
self.assertEqual(len(res), 2, "The result should contain 2 elements")
|
||||
self.assertIsInstance(res[0], basestring)
|
||||
self.assertIsInstance(res[1], (int, long))
|
||||
self.assertIsInstance(res[1], pycompat.integer_types)
|
||||
|
||||
# Check returned values
|
||||
self.assertEqual(res[0], self.expected_path)
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import time
|
||||
import sys
|
||||
|
||||
from odoo import models, api
|
||||
from odoo.tools import pycompat
|
||||
|
||||
class m(models.Model):
|
||||
""" This model exposes a few methods that will consume between 'almost no
|
||||
@@ -37,7 +39,7 @@ class m(models.Model):
|
||||
t0 = time.clock()
|
||||
t1 = time.clock()
|
||||
while t1 - t0 < seconds:
|
||||
for i in xrange(10000000):
|
||||
for i in pycompat.range(10000000):
|
||||
x = i * i
|
||||
t1 = time.clock()
|
||||
return True
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo.tests import common
|
||||
from odoo.tools import pycompat
|
||||
|
||||
ANSWER_TO_ULTIMATE_QUESTION = 42
|
||||
|
||||
@@ -16,7 +17,7 @@ class TestAttributes(common.TransactionCase):
|
||||
self.assertTrue(hasattr(instance, 'unknown'))
|
||||
|
||||
# Is it the right type ?
|
||||
self.assertIsInstance(instance.unknown, (int, long))
|
||||
self.assertIsInstance(instance.unknown, pycompat.integer_types)
|
||||
|
||||
# Is it the right value, in case of, we don't know ;-)
|
||||
self.assertEqual(instance.unknown, ANSWER_TO_ULTIMATE_QUESTION)
|
||||
|
||||
@@ -25,6 +25,21 @@ class TestPyLint(TransactionCase):
|
||||
'E0601', # using variable before assignment
|
||||
'W0123', # eval used
|
||||
'W0101', # unreachable code
|
||||
|
||||
'long-suffix',
|
||||
'apply-builtin',
|
||||
'cmp-builtin',
|
||||
'coerce-builtin',
|
||||
'execfile-builtin',
|
||||
'input-builtin',
|
||||
'intern-builtin',
|
||||
'long-builtin',
|
||||
'raw_input-builtin',
|
||||
'reload-builtin',
|
||||
'xrange-builtin',
|
||||
# TODO: enable once report has been removed
|
||||
# 'file-builtin',
|
||||
# 'reduce-builtin',
|
||||
]
|
||||
|
||||
def _skip_test(self, reason):
|
||||
|
||||
+2
-3
@@ -15,8 +15,7 @@ import xmlrpclib
|
||||
import psycopg2
|
||||
|
||||
from odoo.sql_db import LazyCursor
|
||||
from odoo.tools import float_precision, float_repr, float_round, frozendict, \
|
||||
html_sanitize, human_size, pg_varchar, ustr, OrderedSet
|
||||
from odoo.tools import float_precision, float_repr, float_round, frozendict, html_sanitize, human_size, pg_varchar, ustr, OrderedSet, pycompat
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT
|
||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT as DATETIME_FORMAT
|
||||
from odoo.tools.translate import html_translate, _
|
||||
@@ -1656,7 +1655,7 @@ class Binary(Field):
|
||||
def convert_to_cache(self, value, record, validate=True):
|
||||
if isinstance(value, buffer):
|
||||
return str(value)
|
||||
if isinstance(value, (int, long)) and \
|
||||
if isinstance(value, pycompat.integer_types) 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
|
||||
|
||||
+3
-16
@@ -621,10 +621,10 @@ class JsonRequest(WebRequest):
|
||||
# We need then to manage http sessions manually.
|
||||
response['session_id'] = self.session.sid
|
||||
mime = 'application/javascript'
|
||||
body = "%s(%s);" % (self.jsonp, json.dumps(response),)
|
||||
body = "%s(%s);" % (self.jsonp, json.dumps(response, default=ustr),)
|
||||
else:
|
||||
mime = 'application/json'
|
||||
body = json.dumps(response)
|
||||
body = json.dumps(response, default=ustr)
|
||||
|
||||
return Response(
|
||||
body, headers=[('Content-Type', mime),
|
||||
@@ -695,7 +695,7 @@ def serialize_exception(e):
|
||||
"name": type(e).__module__ + "." + type(e).__name__ if type(e).__module__ else type(e).__name__,
|
||||
"debug": traceback.format_exc(),
|
||||
"message": ustr(e),
|
||||
"arguments": to_jsonable(e.args),
|
||||
"arguments": e.args,
|
||||
"exception_type": "internal_error"
|
||||
}
|
||||
if isinstance(e, odoo.exceptions.UserError):
|
||||
@@ -716,19 +716,6 @@ def serialize_exception(e):
|
||||
tmp["exception_type"] = "except_orm"
|
||||
return tmp
|
||||
|
||||
def to_jsonable(o):
|
||||
if isinstance(o, str) or isinstance(o,unicode) or isinstance(o, int) or isinstance(o, long) \
|
||||
or isinstance(o, bool) or o is None or isinstance(o, float):
|
||||
return o
|
||||
if isinstance(o, list) or isinstance(o, tuple):
|
||||
return [to_jsonable(x) for x in o]
|
||||
if isinstance(o, dict):
|
||||
tmp = {}
|
||||
for k, v in o.items():
|
||||
tmp[u"%s" % k] = to_jsonable(v)
|
||||
return tmp
|
||||
return ustr(o)
|
||||
|
||||
class HttpRequest(WebRequest):
|
||||
""" Handler for the ``http`` request type.
|
||||
|
||||
|
||||
+5
-4
@@ -41,6 +41,7 @@ from lxml import etree
|
||||
from lxml.builder import E
|
||||
|
||||
import odoo
|
||||
from odoo.tools import pycompat
|
||||
from . import SUPERUSER_ID
|
||||
from . import api
|
||||
from . import tools
|
||||
@@ -173,7 +174,7 @@ class NewId(object):
|
||||
def __nonzero__(self):
|
||||
return False
|
||||
|
||||
IdType = (int, long, str, unicode, NewId)
|
||||
IdType = pycompat.integer_types + (str, unicode, NewId)
|
||||
|
||||
|
||||
# maximum number of prefetched records
|
||||
@@ -1391,7 +1392,7 @@ class BaseModel(object):
|
||||
provided domain <reference/orm/domains>`.
|
||||
"""
|
||||
res = self.search(args, count=True)
|
||||
return res if isinstance(res, (int, long)) else len(res)
|
||||
return res if isinstance(res, pycompat.integer_types) else len(res)
|
||||
|
||||
@api.model
|
||||
@api.returns('self',
|
||||
@@ -1536,7 +1537,7 @@ class BaseModel(object):
|
||||
# override defaults with the provided values, never allow the other way around
|
||||
defaults = self.default_get(list(missing_defaults))
|
||||
for name, value in defaults.iteritems():
|
||||
if self._fields[name].type == 'many2many' and value and isinstance(value[0], (int, long)):
|
||||
if self._fields[name].type == 'many2many' and value and isinstance(value[0], pycompat.integer_types):
|
||||
# convert a list of ids into a list of commands
|
||||
defaults[name] = [(6, 0, value)]
|
||||
elif self._fields[name].type == 'one2many' and value and isinstance(value[0], dict):
|
||||
@@ -3862,7 +3863,7 @@ class BaseModel(object):
|
||||
"""
|
||||
ids, new_ids = [], []
|
||||
for i in self._ids:
|
||||
(ids if isinstance(i, (int, long)) else new_ids).append(i)
|
||||
(ids if isinstance(i, pycompat.integer_types) else new_ids).append(i)
|
||||
if not ids:
|
||||
return self
|
||||
query = """SELECT id FROM "%s" WHERE id IN %%s""" % self._table
|
||||
|
||||
@@ -165,7 +165,7 @@ class Node(object):
|
||||
for attr in ('init', 'update', 'demo'):
|
||||
if hasattr(self, attr):
|
||||
setattr(node, attr, True)
|
||||
self.children.sort(lambda x, y: cmp(x.name, y.name))
|
||||
self.children.sort(key=lambda x: x.name)
|
||||
return node
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
|
||||
@@ -137,7 +137,8 @@ class MigrationManager(object):
|
||||
try:
|
||||
fp, fname = tools.file_open(pyfile, pathinfo=True)
|
||||
|
||||
if not isinstance(fp, file):
|
||||
# FIXME: imp.load_source removed in P3, and so is the ``file`` object...
|
||||
if not isinstance(fp, file):# pylint: disable=file-builtin
|
||||
# imp.load_source need a real file object, so we create
|
||||
# one from the file-like object we get from file_open
|
||||
fp2 = os.tmpfile()
|
||||
|
||||
@@ -78,7 +78,7 @@ class AddonsHook(object):
|
||||
|
||||
# execute source in context of module *after* putting everything in
|
||||
# sys.modules, so recursive import works
|
||||
execfile(modfile, new_mod.__dict__)
|
||||
exec(open(modfile, 'rb').read(), new_mod.__dict__)
|
||||
|
||||
# people import openerp.addons and expect openerp.addons.<module> to work
|
||||
setattr(odoo.addons, addon_name, new_mod)
|
||||
|
||||
@@ -121,6 +121,7 @@ from functools import partial
|
||||
from zlib import crc32
|
||||
|
||||
import odoo.modules
|
||||
from odoo.tools import pycompat
|
||||
from ..models import MAGIC_COLUMNS, BaseModel
|
||||
import odoo.tools as tools
|
||||
|
||||
@@ -700,7 +701,7 @@ class expression(object):
|
||||
names = [value]
|
||||
elif value and isinstance(value, (tuple, list)) and all(isinstance(item, basestring) for item in value):
|
||||
names = value
|
||||
elif isinstance(value, (int, long)):
|
||||
elif isinstance(value, pycompat.integer_types):
|
||||
return [value]
|
||||
if names:
|
||||
return list({
|
||||
|
||||
@@ -10,6 +10,7 @@ import time
|
||||
import odoo
|
||||
from odoo.exceptions import UserError, ValidationError, QWebException
|
||||
from odoo.models import check_method_name
|
||||
from odoo.tools import pycompat
|
||||
from odoo.tools.translate import translate
|
||||
from odoo.tools.translate import _
|
||||
|
||||
@@ -63,7 +64,7 @@ def check(f):
|
||||
|
||||
|
||||
uid = 1
|
||||
if args and isinstance(args[0], (long, int)):
|
||||
if args and isinstance(args[0], pycompat.integer_types):
|
||||
uid = args[0]
|
||||
|
||||
lang = ctx and ctx.get('lang')
|
||||
@@ -83,7 +84,7 @@ def check(f):
|
||||
if args and len(args) > 1:
|
||||
# TODO self doesn't exist, but was already wrong before (it was not a registry but just the object_service.
|
||||
obj = self.get(args[1])
|
||||
if len(args) > 3 and isinstance(args[3], (long, int, list)):
|
||||
if len(args) > 3 and isinstance(args[3], (pycompat.integer_types, list)):
|
||||
ids = args[3]
|
||||
else:
|
||||
ids = []
|
||||
|
||||
@@ -863,7 +863,7 @@ def _reexec(updated_modules=None):
|
||||
|
||||
def load_test_file_yml(registry, test_file):
|
||||
with registry.cursor() as cr:
|
||||
odoo.tools.convert_yaml_import(cr, 'base', file(test_file), 'test', {}, 'init')
|
||||
odoo.tools.convert_yaml_import(cr, 'base', open(test_file, 'rb'), 'test', {}, 'init')
|
||||
if config['test_commit']:
|
||||
_logger.info('test %s has been commited', test_file)
|
||||
cr.commit()
|
||||
|
||||
+4
-4
@@ -21,6 +21,8 @@ import psycopg2.extensions
|
||||
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_REPEATABLE_READ
|
||||
from psycopg2.pool import PoolError
|
||||
|
||||
from .tools import pycompat
|
||||
|
||||
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
@@ -255,10 +257,8 @@ class Cursor(object):
|
||||
sum = 0
|
||||
if sqllogs[type]:
|
||||
sqllogitems = sqllogs[type].items()
|
||||
sqllogitems.sort(key=lambda k: k[1][1])
|
||||
_logger.debug("SQL LOG %s:", type)
|
||||
sqllogitems.sort(lambda x, y: cmp(x[1][0], y[1][0]))
|
||||
for r in sqllogitems:
|
||||
for r in sorted(sqllogitems, key=lambda k: k[1]):
|
||||
delay = timedelta(microseconds=r[1][1])
|
||||
_logger.debug("table: %s: %s/%s", r[0], delay, r[1][0])
|
||||
sum += r[1][1]
|
||||
@@ -469,7 +469,7 @@ class LazyCursor(object):
|
||||
if cr is None:
|
||||
from odoo import registry
|
||||
cr = self._cursor = registry(self.dbname).cursor()
|
||||
for _ in xrange(self._depth):
|
||||
for _ in pycompat.range(self._depth):
|
||||
cr.__enter__()
|
||||
return getattr(cr, name)
|
||||
|
||||
|
||||
@@ -367,7 +367,7 @@ class HttpCase(TransactionCase):
|
||||
_logger.info('phantomjs unlink localstorage %s', i)
|
||||
os.unlink(i)
|
||||
try:
|
||||
phantom = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=None)
|
||||
phantom = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=None, close_fds=True)
|
||||
except OSError:
|
||||
raise unittest.SkipTest("PhantomJS not found")
|
||||
result = False
|
||||
|
||||
@@ -549,7 +549,7 @@ class configmanager(object):
|
||||
if not rc_exists and not os.path.exists(os.path.dirname(self.rcfile)):
|
||||
os.makedirs(os.path.dirname(self.rcfile))
|
||||
try:
|
||||
p.write(file(self.rcfile, 'w'))
|
||||
p.write(open(self.rcfile, 'w'))
|
||||
if not rc_exists:
|
||||
os.chmod(self.rcfile, 0o600)
|
||||
except IOError:
|
||||
|
||||
@@ -890,10 +890,10 @@ def convert_xml_import(cr, module, xmlfile, idref=None, mode='init', noupdate=Fa
|
||||
|
||||
if idref is None:
|
||||
idref={}
|
||||
if isinstance(xmlfile, file):
|
||||
xml_filename = xmlfile.name
|
||||
else:
|
||||
if isinstance(xmlfile, basestring):
|
||||
xml_filename = xmlfile
|
||||
else:
|
||||
xml_filename = xmlfile.name
|
||||
obj = xml_import(cr, module, idref, mode, report=report, noupdate=noupdate, xml_filename=xml_filename)
|
||||
obj.parse(doc.getroot(), mode=mode)
|
||||
return True
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
from __future__ import print_function
|
||||
import math
|
||||
|
||||
from odoo.tools import pycompat
|
||||
|
||||
|
||||
def _float_check_precision(precision_digits=None, precision_rounding=None):
|
||||
assert (precision_digits is not None or precision_rounding is not None) and \
|
||||
not (precision_digits and precision_rounding),\
|
||||
@@ -54,7 +57,7 @@ def float_round(value, precision_digits=None, precision_rounding=None, rounding_
|
||||
epsilon_magnitude = math.log(abs(normalized_value), 2)
|
||||
epsilon = 2**(epsilon_magnitude-53)
|
||||
if rounding_method == 'HALF-UP':
|
||||
normalized_value += cmp(normalized_value,0) * epsilon
|
||||
normalized_value += math.copysign(epsilon, normalized_value)
|
||||
rounded_value = round(normalized_value) # round to integer
|
||||
|
||||
# TIE-BREAKING: UP (for ceiling operations)
|
||||
@@ -66,7 +69,7 @@ def float_round(value, precision_digits=None, precision_rounding=None, rounding_
|
||||
# restored.
|
||||
|
||||
elif rounding_method == 'UP':
|
||||
sign = cmp(normalized_value, 0)
|
||||
sign = math.copysign(1.0, normalized_value)
|
||||
normalized_value -= sign*epsilon
|
||||
rounded_value = math.ceil(abs(normalized_value))*sign # ceil to integer
|
||||
|
||||
@@ -214,14 +217,13 @@ if __name__ == "__main__":
|
||||
fractions = [.0, .015, .01499, .675, .67499, .4555, .4555, .45555]
|
||||
expecteds = ['.00', '.02', '.01', '.68', '.67', '.46', '.456', '.4556']
|
||||
precisions = [2, 2, 2, 2, 2, 2, 3, 4]
|
||||
for magnitude in range(7):
|
||||
for i in xrange(len(fractions)):
|
||||
frac, exp, prec = fractions[i], expecteds[i], precisions[i]
|
||||
for magnitude in pycompat.range(7):
|
||||
for frac, exp, prec in zip(fractions, expecteds, precisions):
|
||||
for sign in [-1,1]:
|
||||
for x in xrange(0,10000,97):
|
||||
for x in pycompat.range(0, 10000, 97):
|
||||
n = x * 10**magnitude
|
||||
f = sign * (n + frac)
|
||||
f_exp = ('-' if f != 0 and sign == -1 else '') + str(n) + exp
|
||||
f_exp = ('-' if f != 0 and sign == -1 else '') + str(n) + exp
|
||||
try_round(f, f_exp, precision_digits=prec)
|
||||
|
||||
stop = time.time()
|
||||
|
||||
+1
-1
@@ -634,7 +634,7 @@ class graph(object):
|
||||
self.init_order(self.start, self.result[self.start]['x'])
|
||||
|
||||
for level in self.levels:
|
||||
self.levels[level].sort(lambda x, y: cmp(self.result[x]['y'], self.result[y]['y']))
|
||||
self.levels[level].sort(key=lambda x: self.result[x]['y'])
|
||||
|
||||
self.order_heuristic()
|
||||
self.process_order()
|
||||
|
||||
+2
-2
@@ -280,6 +280,6 @@ if __name__=="__main__":
|
||||
|
||||
assert len(sys.argv)==3, 'Usage to Test: image.py SRC.png DEST.png'
|
||||
|
||||
img = file(sys.argv[1],'rb').read().encode('base64')
|
||||
img = open(sys.argv[1],'rb').read().encode('base64')
|
||||
new = image_resize_image(img, (128,100))
|
||||
file(sys.argv[2], 'wb').write(new.decode('base64'))
|
||||
open(sys.argv[2], 'wb').write(new.decode('base64'))
|
||||
|
||||
@@ -125,7 +125,7 @@ class ReceiverEmail2Event(object):
|
||||
os.mkdir(newdir)
|
||||
|
||||
counter += 1
|
||||
fd = file(os.path.join(newdir, filename), 'w')
|
||||
fd = open(os.path.join(newdir, filename), 'w')
|
||||
fd.write(part.get_payload(decode=1))
|
||||
fd.close()
|
||||
else:
|
||||
|
||||
+42
-4
@@ -27,6 +27,7 @@ from cStringIO import StringIO
|
||||
from collections import defaultdict, Iterable, Mapping, MutableSet, OrderedDict
|
||||
from itertools import islice, izip, groupby, repeat
|
||||
from lxml import etree
|
||||
|
||||
from which import which
|
||||
from threading import local
|
||||
import traceback
|
||||
@@ -41,6 +42,7 @@ except ImportError:
|
||||
from config import config
|
||||
from cache import *
|
||||
from .parse_version import parse_version
|
||||
from . import pycompat
|
||||
|
||||
import odoo
|
||||
# get_encodings, ustr and exception_to_unicode were originally from tools.misc.
|
||||
@@ -279,7 +281,7 @@ def flatten(list):
|
||||
return r
|
||||
|
||||
def reverse_enumerate(l):
|
||||
"""Like enumerate but in the other sens
|
||||
"""Like enumerate but in the other direction
|
||||
|
||||
Usage::
|
||||
>>> a = ['a', 'b', 'c']
|
||||
@@ -295,7 +297,7 @@ def reverse_enumerate(l):
|
||||
File "<stdin>", line 1, in <module>
|
||||
StopIteration
|
||||
"""
|
||||
return izip(xrange(len(l)-1, -1, -1), reversed(l))
|
||||
return izip(pycompat.range(len(l)-1, -1, -1), reversed(l))
|
||||
|
||||
def partition(pred, elems):
|
||||
""" Return a pair equivalent to:
|
||||
@@ -654,8 +656,11 @@ def posix_to_ldml(fmt, locale):
|
||||
def split_every(n, iterable, piece_maker=tuple):
|
||||
"""Splits an iterable into length-n pieces. The last piece will be shorter
|
||||
if ``n`` does not evenly divide the iterable length.
|
||||
@param ``piece_maker``: function to build the pieces
|
||||
from the slices (tuple,list,...)
|
||||
|
||||
:param int n: maximum size of each generated chunk
|
||||
:param Iterable iterable: iterable to chunk into pieces
|
||||
:param piece_maker: callable taking an iterable and collecting each
|
||||
chunk from its slice, *must consume the entire slice*.
|
||||
"""
|
||||
iterator = iter(iterable)
|
||||
piece = piece_maker(islice(iterator, n))
|
||||
@@ -990,6 +995,39 @@ class LastOrderedSet(OrderedSet):
|
||||
OrderedSet.discard(self, elem)
|
||||
OrderedSet.add(self, elem)
|
||||
|
||||
def unique(it):
|
||||
""" "Uniquifier" for the provided iterable: will output each element of
|
||||
the iterable once.
|
||||
|
||||
The iterable's elements must be hashahble.
|
||||
|
||||
:param Iterable it:
|
||||
:rtype: Iterator
|
||||
"""
|
||||
seen = set()
|
||||
for e in it:
|
||||
if e not in seen:
|
||||
seen.add(e)
|
||||
yield e
|
||||
|
||||
class Reverse(object):
|
||||
""" Wraps a value and reverses its ordering, useful in key functions when
|
||||
mixing ascending and descending sort on non-numeric data as the
|
||||
``reverse`` parameter can not do piecemeal reordering.
|
||||
"""
|
||||
__slots__ = ['val']
|
||||
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
|
||||
def __eq__(self, other): return self.val == other.val
|
||||
def __ne__(self, other): return self.val != other.val
|
||||
|
||||
def __ge__(self, other): return self.val <= other.val
|
||||
def __gt__(self, other): return self.val < other.val
|
||||
def __le__(self, other): return self.val >= other.val
|
||||
def __lt__(self, other): return self.val > other.val
|
||||
|
||||
@contextmanager
|
||||
def ignore(*exc):
|
||||
try:
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# to remove if we decide to add a dependency on six or future
|
||||
# very strongly inspired by https://github.com/pallets/werkzeug/blob/master/werkzeug/_compat.py
|
||||
import sys
|
||||
|
||||
PY2 = sys.version_info[0]
|
||||
|
||||
if PY2:
|
||||
# pylint: disable=long-builtin,xrange-builtin
|
||||
integer_types = (int, long)
|
||||
|
||||
range = xrange
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from itertools import imap, izip, ifilter
|
||||
|
||||
def implements_iterator(cls):
|
||||
cls.next = cls.__next__
|
||||
del cls.__next__
|
||||
return cls
|
||||
else:
|
||||
integer_types = (int,)
|
||||
|
||||
range = range
|
||||
|
||||
imap = map
|
||||
izip = zip
|
||||
ifilter = filter
|
||||
|
||||
def implements_iterator(cls):
|
||||
return cls
|
||||
@@ -16,11 +16,14 @@ condition/math builtins.
|
||||
# - safe_eval in tryton http://hg.tryton.org/hgwebdir.cgi/trytond/rev/bbb5f73319ad
|
||||
|
||||
from opcode import HAVE_ARGUMENT, opmap
|
||||
|
||||
import functools
|
||||
from psycopg2 import OperationalError
|
||||
from types import CodeType
|
||||
import logging
|
||||
import werkzeug
|
||||
|
||||
from odoo.tools import pycompat
|
||||
from .misc import ustr
|
||||
|
||||
import odoo
|
||||
@@ -226,7 +229,6 @@ _BUILTINS = {
|
||||
'bool': bool,
|
||||
'int': int,
|
||||
'float': float,
|
||||
'long': long,
|
||||
'enumerate': enumerate,
|
||||
'dict': dict,
|
||||
'list': list,
|
||||
@@ -236,7 +238,7 @@ _BUILTINS = {
|
||||
'min': min,
|
||||
'max': max,
|
||||
'sum': sum,
|
||||
'reduce': reduce,
|
||||
'reduce': functools.reduce,
|
||||
'filter': filter,
|
||||
'round': round,
|
||||
'len': len,
|
||||
@@ -246,11 +248,10 @@ _BUILTINS = {
|
||||
'any': any,
|
||||
'ord': ord,
|
||||
'chr': chr,
|
||||
'cmp': cmp,
|
||||
'divmod': divmod,
|
||||
'isinstance': isinstance,
|
||||
'range': range,
|
||||
'xrange': xrange,
|
||||
'xrange': pycompat.range,
|
||||
'zip': zip,
|
||||
'Exception': Exception,
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ import odoo
|
||||
import odoo.report
|
||||
import odoo.tools as tools
|
||||
import logging
|
||||
|
||||
from odoo.tools import pycompat
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
from subprocess import Popen, PIPE
|
||||
import os
|
||||
@@ -45,7 +47,7 @@ def try_report(cr, uid, rname, ids, data=None, context=None, our_module=None, re
|
||||
raise ValueError("Report %s produced an empty result!" % rname)
|
||||
|
||||
if tools.config['test_report_directory']:
|
||||
file(os.path.join(tools.config['test_report_directory'], rname+ '.'+res_format), 'wb+').write(res_data)
|
||||
open(os.path.join(tools.config['test_report_directory'], rname+ '.'+res_format), 'wb+').write(res_data)
|
||||
|
||||
_logger.debug("Have a %s report for %s, will examine it", res_format, rname)
|
||||
if res_format == 'pdf':
|
||||
@@ -128,7 +130,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, (long, int))
|
||||
assert isinstance(action_id, pycompat.integer_types)
|
||||
act_model = 'ir.action.act_window' # assume that
|
||||
act_id = action_id
|
||||
act_xmlid = '<%s>' % act_id
|
||||
|
||||
@@ -20,7 +20,7 @@ from babel.messages import extract
|
||||
from lxml import etree
|
||||
|
||||
import odoo
|
||||
from odoo.tools import config
|
||||
from odoo.tools import config, pycompat
|
||||
from odoo.tools.misc import file_open, get_iso_codes, SKIPPED_ELEMENT_TYPES
|
||||
from odoo.tools.osutil import walksymlinks
|
||||
from odoo import sql_db, SUPERUSER_ID
|
||||
@@ -679,7 +679,7 @@ def trans_export(lang, modules, buffer, format, cr):
|
||||
tmpmoddir = join(tmpdir, mod, 'i18n')
|
||||
os.makedirs(tmpmoddir)
|
||||
pofilename = (lang if lang else mod) + ".po" + ('t' if not lang else '')
|
||||
buf = file(join(tmpmoddir, pofilename), 'w')
|
||||
buf = open(join(tmpmoddir, pofilename), 'w')
|
||||
_process('po', [mod], modrows, buf, lang)
|
||||
buf.close()
|
||||
|
||||
@@ -1106,7 +1106,7 @@ def trans_load_data(cr, fileobj, fileformat, lang, lang_name=None, verbose=True,
|
||||
if not res_id:
|
||||
return
|
||||
|
||||
if isinstance(res_id, (int, long)) or \
|
||||
if isinstance(res_id, pycompat.integer_types) or \
|
||||
(isinstance(res_id, basestring) and res_id.isdigit()):
|
||||
dic['res_id'] = int(res_id)
|
||||
if module_name:
|
||||
|
||||
@@ -8,7 +8,7 @@ from setuptools import find_packages, setup
|
||||
from os.path import join, dirname
|
||||
|
||||
|
||||
execfile(join(dirname(__file__), 'odoo', 'release.py')) # Load release variables
|
||||
exec(open(join(dirname(__file__), 'odoo', 'release.py'), 'rb').read()) # Load release variables
|
||||
lib_name = 'odoo'
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ from tempfile import NamedTemporaryFile
|
||||
#----------------------------------------------------------
|
||||
# Utils
|
||||
#----------------------------------------------------------
|
||||
execfile(join(dirname(__file__), '..', 'odoo', 'release.py'))
|
||||
exec(open(join(dirname(__file__), '..', 'odoo', 'release.py'), 'rb').read())
|
||||
version = version.split('-')[0]
|
||||
docker_version = version.replace('+', '')
|
||||
timestamp = time.strftime("%Y%m%d", time.gmtime())
|
||||
|
||||
@@ -11,7 +11,7 @@ import sys
|
||||
from os.path import dirname, join, split
|
||||
|
||||
|
||||
execfile(join(dirname(__file__), '..', 'server', 'odoo', 'release.py'))
|
||||
exec(open(join(dirname(__file__), '..', 'server', 'odoo', 'release.py'), 'rb').read())
|
||||
|
||||
|
||||
class OdooService(win32serviceutil.ServiceFramework):
|
||||
|
||||
@@ -6,7 +6,7 @@ import py2exe
|
||||
from distutils.core import setup
|
||||
|
||||
|
||||
execfile(os.path.join(os.path.dirname(__file__), '..', '..', 'odoo', 'release.py'))
|
||||
exec(open(os.path.join(os.path.dirname(__file__), '..', '..', 'odoo', 'release.py'), 'rb').read())
|
||||
|
||||
|
||||
def generate_files():
|
||||
|
||||
Reference in New Issue
Block a user