Remove support for Python 2.7

issue7497
review53261002
This commit is contained in:
Cédric Krier committed 2018-06-26 19:11:19 +02:00
1 parent d81519d312
commit d2a461390a
106 files changed
+1137 -1230

No files matched your search

-6
View File
@@ -25,12 +25,6 @@ services:
matrix:
include:
- IMAGE: python:2.7
TOXENV: py27
DATABASE: sqlite
- IMAGE: python:2.7
TOXENV: py27
DATABASE: postgresql
- IMAGE: python:3.4
TOXENV: py34
DATABASE: sqlite
+1
View File
@@ -1,3 +1,4 @@
* Remove support for Python 2.7
* Check Rule also after modification
* Check Rule after indirect fields
* Allow to define view id in switch client action
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import sys
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import sys
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import sys
+4 -4
View File
@@ -39,8 +39,8 @@ source_suffix = '.rst'
master_doc = 'index'
# General information about the project.
project = u'trytond'
copyright = (u'2008-2011, Bertrand Chenal, Cédric Krier, Ian Wilson, '
project = 'trytond'
copyright = ('2008-2011, Bertrand Chenal, Cédric Krier, Ian Wilson, '
'Udo Spallek')
# The version info for the project you're documenting, acts as replacement for
@@ -175,8 +175,8 @@ htmlhelp_basename = 'trytonddoc'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual])
latex_documents = [
('index', 'trytond.tex', u'trytond Documentation',
u'Bertrand Chenal, Cédric Krier, Ian Wilson, Udo Spallek', 'manual'),
('index', 'trytond.tex', 'trytond Documentation',
'Bertrand Chenal, Cédric Krier, Ian Wilson, Udo Spallek', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
+3 -3
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
@@ -19,6 +19,7 @@ def get_version():
init = read(os.path.join('trytond', '__init__.py'))
return re.search('__version__ = "([0-9.]*)"', init).group(1)
version = get_version()
major_version, minor_version, _ = version.split('.', 2)
major_version = int(major_version)
@@ -83,7 +84,6 @@ setup(name=name,
'Natural Language :: Slovenian',
'Natural Language :: Spanish',
'Operating System :: OS Independent',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
@@ -93,6 +93,7 @@ setup(name=name,
],
platforms='any',
license='GPL-3',
python_requires='>=3.4',
install_requires=[
'lxml >= 2.0',
'relatorio[fodt] >= 0.7.0',
@@ -116,5 +117,4 @@ setup(name=name,
test_suite='trytond.tests',
test_loader='trytond.test_loader:Loader',
tests_require=['mock'],
use_2to3=True,
)
+3 -3
View File
@@ -1,12 +1,12 @@
[tox]
envlist = {py27,py34,py35,py36}-{sqlite,postgresql},pypy-{sqlite,postgresql}
envlist = {py34,py35,py36}-{sqlite,postgresql},pypy3-{sqlite,postgresql}
[testenv]
commands = {envpython} setup.py test
deps =
mock
{py27,py34,py35,py36}-postgresql: psycopg2 >= 2.5
pypy-postgresql: psycopg2cffi >= 2.5
{py34,py35,py36}-postgresql: psycopg2 >= 2.5
pypy3-postgresql: psycopg2cffi >= 2.5
sqlite: sqlitebck
setenv =
sqlite: TRYTOND_DATABASE_URI={env:SQLITE_URI:sqlite://}
+2 -2
View File
@@ -80,7 +80,7 @@ def run(options):
if options.email is not None:
admin.email = options.email
elif init[db_name]:
admin.email = raw_input(
admin.email = input(
'"admin" email for "%s": ' % db_name)
if init[db_name] or options.password:
# try to read password from environment variable
@@ -91,7 +91,7 @@ def run(options):
try:
with open(passpath) as passfile:
password, = passfile.read().splitlines()
except Exception, err:
except Exception as err:
sys.stderr.write('Can not read password '
'from "%s": "%s"\n' % (passpath, err))
+1 -1
View File
@@ -20,6 +20,6 @@ Pool.start()
db_names = os.environ.get('TRYTOND_DATABASE_NAMES')
if db_names:
# Read with csv so database name can include special chars
reader = csv.reader(StringIO(unicode(db_names)))
reader = csv.reader(StringIO(db_names))
for db_name in next(reader):
Pool(db_name).init()
+3 -3
View File
@@ -1,7 +1,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import sys
import urlparse
import urllib.parse
import os
import imp
try:
@@ -15,7 +15,7 @@ __all__ = ['name', 'get']
def name():
return urlparse.urlparse(config.get('database', 'uri', default='')).scheme
return urllib.parse.urlparse(config.get('database', 'uri', default='')).scheme
def get(prop):
@@ -24,7 +24,7 @@ def get(prop):
if modname not in sys.modules:
try:
__import__(modname)
except ImportError, exception:
except ImportError as exception:
if not pkg_resources:
raise exception
try:
+3 -3
View File
@@ -3,7 +3,7 @@
import time
import logging
import os
import urllib
import urllib.request, urllib.parse, urllib.error
import json
from decimal import Decimal
from threading import RLock
@@ -49,7 +49,7 @@ def unescape_quote(s):
def replace_special_values(s, **mapping):
for name, value in mapping.iteritems():
for name, value in mapping.items():
s = s.replace('$' + name, value)
return s
@@ -111,7 +111,7 @@ class Database(DatabaseInterface):
port = uri.port and "port=%s" % uri.port or ''
name = "dbname=%s" % name
user = uri.username and "user=%s" % uri.username or ''
password = ("password=%s" % urllib.unquote_plus(uri.password)
password = ("password=%s" % urllib.parse.unquote_plus(uri.password)
if uri.password else '')
return '%s %s %s %s %s' % (host, port, name, user, password)
+1 -1
View File
@@ -329,7 +329,7 @@ class TableHandler(TableHandlerInterface):
self.drop_constraint(column_name + '_fkey', table=table)
def index_action(self, column_name, action='add', table=None):
if isinstance(column_name, basestring):
if isinstance(column_name, str):
column_name = [column_name]
index_name = self.convert_name(
((table or self.table_name) + "_" + '_'.join(column_name) +
+13 -17
View File
@@ -1,14 +1,11 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.backend.database import DatabaseInterface, SQLType
from trytond.config import config
import os
from decimal import Decimal
import datetime
import time
import sys
import threading
import logging
import os
import threading
import time
from decimal import Decimal
_FIX_ROWCOUNT = False
try:
@@ -25,6 +22,9 @@ from sql import Flavor, Table, Query, Expression
from sql.functions import (Function, Extract, Position, Substring,
Overlay, CharLength, CurrentTimestamp, Trim)
from trytond.backend.database import DatabaseInterface, SQLType
from trytond.config import config
__all__ = ['Database', 'DatabaseIntegrityError', 'DatabaseOperationalError']
logger = logging.getLogger(__name__)
@@ -171,7 +171,7 @@ class SQLiteTrim(Trim):
}[self.position]
def format(arg):
if isinstance(arg, basestring):
if isinstance(arg, str):
return param
else:
return str(arg)
@@ -189,7 +189,7 @@ def sign(value):
def greatest(*args):
args = filter(lambda a: a is not None, args)
args = [a for a in args if a is not None]
if args:
return max(args)
else:
@@ -197,7 +197,7 @@ def greatest(*args):
def least(*args):
args = filter(lambda a: a is not None, args)
args = [a for a in args if a is not None]
if args:
return min(args)
else:
@@ -440,19 +440,15 @@ class Database(DatabaseInterface):
return value
sqlite.register_converter('NUMERIC', lambda val: Decimal(val.decode('utf-8')))
if sys.version_info[0] == 2:
sqlite.register_adapter(Decimal, lambda val: buffer(str(val)))
sqlite.register_adapter(bytearray, lambda val: buffer(val))
else:
sqlite.register_adapter(Decimal, lambda val: str(val).encode('utf-8'))
sqlite.register_adapter(Decimal, lambda val: str(val).encode('utf-8'))
def adapt_datetime(val):
return val.replace(tzinfo=None).isoformat(" ")
sqlite.register_adapter(datetime.datetime, adapt_datetime)
sqlite.register_adapter(datetime.time, lambda val: val.isoformat())
sqlite.register_converter('TIME', lambda val: datetime.time(*map(int,
val.decode('utf-8').split(':'))))
sqlite.register_converter('TIME',
lambda val: datetime.time(*map(int, val.decode('utf-8').split(':'))))
sqlite.register_adapter(datetime.timedelta, lambda val: val.total_seconds())
+4 -4
View File
@@ -97,7 +97,7 @@ class TableHandler(TableHandlerInterface):
TableHandler.table_rename(self.table_name, temp_table)
new_table = TableHandler(self._model, history=self.history)
columns, old_columns = [], []
for column, values in self._columns.iteritems():
for column, values in self._columns.items():
typname = new_columns.get(column, {}).get(
'typname', values['typname'])
size = new_columns.get(column, {}).get('size', values['size'])
@@ -244,7 +244,7 @@ class TableHandler(TableHandlerInterface):
warnings.warn('Unable to drop foreign key with SQLite backend')
def index_action(self, column_name, action='add', table=None):
if isinstance(column_name, basestring):
if isinstance(column_name, str):
column_name = [column_name]
index_name = self.convert_name(
self.table_name + "_" + '_'.join(column_name) + "_index")
@@ -296,13 +296,13 @@ class TableHandler(TableHandlerInterface):
temp_table = '_temp_%s' % self.table_name
TableHandler.table_rename(self.table_name, temp_table)
new_table = TableHandler(self._model, history=self.history)
for name, values in self._columns.iteritems():
for name, values in self._columns.items():
if name != column_name:
typname = values['typname']
size = values['size']
new_table._add_raw_column(
name, database.sql_type(typname), field_size=size)
columns_name = [x for x in new_table._columns.keys()]
columns_name = list(new_table._columns.keys())
cursor.execute(('INSERT INTO "%s" (' +
','.join('"%s"' % c for c in columns_name) +
') SELECT ' +
+1 -1
View File
@@ -187,7 +187,7 @@ class TableHandlerInterface(object):
:param name: the data name
'''
if cls.namedatalen and len(name) >= cls.namedatalen:
if isinstance(name, unicode):
if isinstance(name, str):
name = name.encode('utf-8')
name = hashlib.sha256(name).hexdigest()[:cls.namedatalen - 1]
return name
+1 -1
View File
@@ -17,7 +17,7 @@ def freeze(o):
if isinstance(o, (set, tuple, list)):
return tuple(freeze(x) for x in o)
elif isinstance(o, dict):
return frozenset((x, freeze(y)) for x, y in o.iteritems())
return frozenset((x, freeze(y)) for x, y in o.items())
else:
return o
+15 -15
View File
@@ -1,8 +1,8 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import os
import ConfigParser
import urlparse
import configparser
import urllib.parse
import logging
__all__ = ['config', 'get_hostname', 'get_port', 'split_netloc',
@@ -34,13 +34,13 @@ def parse_listen(value):
def parse_uri(uri):
return urlparse.urlparse(uri)
return urllib.parse.urlparse(uri)
class TrytonConfigParser(ConfigParser.RawConfigParser):
class TrytonConfigParser(configparser.RawConfigParser):
def __init__(self):
ConfigParser.RawConfigParser.__init__(self)
configparser.RawConfigParser.__init__(self)
self.add_section('web')
self.set('web', 'listen', 'localhost:8000')
self.set('web', 'root', os.path.join(os.path.expanduser('~'), 'www'))
@@ -77,9 +77,9 @@ class TrytonConfigParser(ConfigParser.RawConfigParser):
self.update_etc()
def update_etc(self, configfile=os.environ.get('TRYTOND_CONFIG')):
if isinstance(configfile, basestring):
if isinstance(configfile, str):
configfile = [configfile]
if not configfile or not filter(None, configfile):
if not configfile or not [_f for _f in configfile if _f]:
return
configfile = [os.path.expanduser(filename) for filename in configfile]
read_files = self.read(configfile)
@@ -88,35 +88,35 @@ class TrytonConfigParser(ConfigParser.RawConfigParser):
def get(self, section, option, *args, **kwargs):
default = kwargs.pop('default', None)
try:
return ConfigParser.RawConfigParser.get(self, section, option,
return configparser.RawConfigParser.get(self, section, option,
*args, **kwargs)
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
except (configparser.NoOptionError, configparser.NoSectionError):
return default
def getint(self, section, option, *args, **kwargs):
default = kwargs.pop('default', None)
try:
return ConfigParser.RawConfigParser.getint(self, section, option,
return configparser.RawConfigParser.getint(self, section, option,
*args, **kwargs)
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError,
except (configparser.NoOptionError, configparser.NoSectionError,
TypeError):
return default
def getfloat(self, section, option, *args, **kwargs):
default = kwargs.pop('default', None)
try:
return ConfigParser.RawConfigParser.getfloat(self, section, option,
return configparser.RawConfigParser.getfloat(self, section, option,
*args, **kwargs)
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError,
except (configparser.NoOptionError, configparser.NoSectionError,
TypeError):
return default
def getboolean(self, section, option, *args, **kwargs):
default = kwargs.pop('default', None)
try:
return ConfigParser.RawConfigParser.getboolean(
return configparser.RawConfigParser.getboolean(
self, section, option, *args, **kwargs)
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError,
except (configparser.NoOptionError, configparser.NoSectionError,
AttributeError):
return default
+9 -9
View File
@@ -5,7 +5,7 @@ import datetime
from xml import sax
import logging
import re
from itertools import izip
from collections import defaultdict
from decimal import Decimal
@@ -356,13 +356,13 @@ class Fs2bdAccessor:
self.browserecord[module].setdefault(model_name, {})
Model = self.pool.get(model_name)
if not ids:
ids = self.browserecord[module][model_name].keys()
ids = list(self.browserecord[module][model_name].keys())
models = Model.browse(ids)
for model in models:
if model.id in self.browserecord[module][model_name]:
for cache in Transaction().cache.values():
for cache in (cache, cache.get('_language_cache',
{}).values()):
for cache in (
cache, cache.get('_language_cache', {}).values()):
if (model_name in cache
and model.id in cache[model_name]):
cache[model_name][model.id] = {}
@@ -396,7 +396,7 @@ class Fs2bdAccessor:
('id', 'in', list(sub_record_ids)),
], order=[('id', 'ASC')])
with Transaction().set_context(language='en'):
models = Model.browse(map(int, records))
models = Model.browse(list(map(int, records)))
for model in models:
self.browserecord[module][model_name][model.id] = model
self.fetched_modules.append(module)
@@ -492,10 +492,10 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
def endElement(self, name):
if name == 'data' and self.grouped:
for model, values in self.grouped_creations.iteritems():
for model, values in self.grouped_creations.items():
self.create_records(model, values.values(), values.keys())
self.grouped_creations.clear()
for key, actions in self.grouped_write.iteritems():
for key, actions in self.grouped_write.items():
module, model = key
self.write_records(module, model, *actions)
self.grouped_write.clear()
@@ -701,7 +701,7 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
records = Model.create(vlist)
mdata_values = []
for record, values, fs_id in izip(records, vlist, fs_ids):
for record, values, fs_id in zip(records, vlist, fs_ids):
for key in values:
values[key] = self._clean_value(key, record)
@@ -717,7 +717,7 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
models_data = self.ModelData.create(mdata_values)
for record, values, fs_id, mdata in izip(
for record, values, fs_id, mdata in zip(
records, vlist, fs_ids, models_data):
self.fs2db.set(self.module, fs_id, {
'db_id': record.id,
+1 -1
View File
@@ -9,7 +9,7 @@ class WarningErrorMixin(object):
@classmethod
def _get_error_messages(cls):
return cls._error_messages.values()
return list(cls._error_messages.values())
@classmethod
def raise_user_error(cls, error, error_args=None,
+3 -7
View File
@@ -1,13 +1,9 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import sys
class TrytonException(Exception):
if sys.version_info < (3, ):
def __str__(self):
return unicode(self).encode('utf-8')
pass
class UserError(TrytonException):
@@ -19,7 +15,7 @@ class UserError(TrytonException):
self.code = 1
def __unicode__(self):
return u'%s - %s' % (self.message, self.description)
return '%s - %s' % (self.message, self.description)
class UserWarning(TrytonException):
@@ -33,7 +29,7 @@ class UserWarning(TrytonException):
self.code = 2
def __unicode__(self):
return u'%s - %s' % (self.message, self.description)
return '%s - %s' % (self.message, self.description)
class LoginException(TrytonException):
+1 -1
View File
@@ -32,7 +32,7 @@ class FileStore(object):
filename = self._filename(id, prefix)
dirname = os.path.dirname(filename)
if not os.path.exists(dirname):
os.makedirs(dirname, 0770)
os.makedirs(dirname, 0o770)
collision = 0
while True:
+1 -1
View File
@@ -225,7 +225,7 @@ class ActionKeyword(ModelSQL, ModelView):
for action_keyword in action_keywords:
type_ = action_keyword.action.type
types[type_].append(action_keyword.action.id)
for type_, action_ids in types.iteritems():
for type_, action_ids in types.items():
for value in Action.get_action_values(type_, action_ids):
value['keyword'] = keyword
keywords.append(value)
+1 -1
View File
@@ -17,7 +17,7 @@ __all__ = [
def firstline(description):
try:
return (x for x in description.splitlines() if x.strip()).next()
return next((x for x in description.splitlines() if x.strip()))
except StopIteration:
return ''
+4 -2
View File
@@ -1,12 +1,13 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import time
import locale
import os
import pprint
import time
from lxml import etree
from . import locale
def locale_strftime(lang):
time_locale = {
@@ -34,6 +35,7 @@ def locale_strftime(lang):
time_locale['%p'].append(time.strftime('%p', t).decode('utf-8'))
return time_locale
if __name__ == '__main__':
base = os.path.dirname(__file__)
# Add en as it is not defined in lang.xml
+1 -11
View File
@@ -1,8 +1,6 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from __future__ import absolute_import
import sys
import datetime
import warnings
warnings.filterwarnings('ignore', "", ImportWarning)
@@ -213,8 +211,6 @@ class Lang(DeactivableMixin, ModelSQL, ModelView):
'''
for lang in langs:
date = lang.date
if sys.version_info < (3,):
date = date.encode('utf-8')
try:
datetime_strftime(datetime.datetime.now(), date)
except Exception:
@@ -482,13 +478,7 @@ class Lang(DeactivableMixin, ModelSQL, ModelView):
format = format.replace('%p',
TIME_LOCALE[code]['%p'][datetime.timetuple()[3] < 12 and 0
or 1])
# Encode and decode under Python2 because strftime use bytes/str.
if sys.version_info < (3,):
format = format.encode('utf-8')
result = datetime_strftime(datetime, format)
if sys.version_info < (3,):
result = result.decode('utf-8')
return result
return datetime_strftime(datetime, format)
def get_parent_language(code):
+8 -8
View File
@@ -253,7 +253,7 @@ class ModelField(ModelSQL, ModelView):
where=ir_model.model == model.__name__))
model_fields = {f['name']: f for f in cursor_dict(cursor)}
for field_name, field in model._fields.iteritems():
for field_name, field in model._fields.items():
if hasattr(field, 'model_name'):
relation = field.model_name
elif hasattr(field, 'relation_name'):
@@ -339,7 +339,7 @@ class ModelField(ModelSQL, ModelView):
to_delete = []
if Transaction().context.get('language'):
if fields_names is None:
fields_names = cls._fields.keys()
fields_names = list(cls._fields.keys())
if 'field_description' in fields_names \
or 'help' in fields_names:
@@ -514,7 +514,7 @@ class ModelAccess(ModelSQL, ModelView):
access.update(dict(
(m, {'read': r, 'write': w, 'create': c, 'delete': d})
for m, r, w, c, d in cursor.fetchall()))
for model, maccess in access.iteritems():
for model, maccess in access.items():
cls._get_access_cache.set((user, model), maccess)
return access
@@ -558,7 +558,7 @@ class ModelAccess(ModelSQL, ModelView):
return True
elif field._type == 'reference':
selection = field.selection
if isinstance(selection, basestring):
if isinstance(selection, str):
sel_func = getattr(Model, field.selection)
if not is_instance_method(Model, field.selection):
selection = sel_func()
@@ -703,7 +703,7 @@ class ModelFieldAccess(ModelSQL, ModelView):
group_by=[ir_model.model, model_field.name]))
for m, f, r, w, c, d in cursor.fetchall():
accesses[m][f] = {'read': r, 'write': w, 'create': c, 'delete': d}
for model, maccesses in accesses.iteritems():
for model, maccesses in accesses.items():
cls._get_access_cache.set((user, model), maccesses)
return accesses
@@ -723,7 +723,7 @@ class ModelFieldAccess(ModelSQL, ModelView):
return True
accesses = dict((f, a[mode])
for f, a in cls.get_access([model_name])[model_name].iteritems())
for f, a in cls.get_access([model_name])[model_name].items())
if access:
return accesses
for field in fields:
@@ -1212,7 +1212,7 @@ class ModelData(ModelSQL, ModelView):
@classmethod
def dump_values(cls, values):
return json.dumps(
sorted(values.iteritems()), cls=JSONEncoder, separators=(',', ':'))
sorted(values.items()), cls=JSONEncoder, separators=(',', ':'))
@classmethod
def load_values(cls, values):
@@ -1245,7 +1245,7 @@ class ModelData(ModelSQL, ModelView):
to_write.extend([[data], {
'values': cls.dump_values(fs_values),
}])
for Model, values_to_write in models_to_write.iteritems():
for Model, values_to_write in models_to_write.items():
Model.write(*values_to_write)
if to_write:
cls.write(*to_write)
+1 -2
View File
@@ -1,6 +1,5 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from __future__ import division
from functools import wraps
@@ -160,7 +159,7 @@ class Module(ModelSQL, ModelView):
child_ids = dict((m.id, []) for m in modules)
name2id = dict((m.name, m.id) for m in modules)
childs = cls.search([
('dependencies.name', 'in', name2id.keys()),
('dependencies.name', 'in', list(name2id.keys())),
])
for child in childs:
for dep in child.dependencies:
+2 -2
View File
@@ -237,11 +237,11 @@ class Rule(ModelSQL, ModelView):
if fetchone:
group_id = fetchone[0]
clause[group_id] = []
clause = clause.values()
clause = list(clause.values())
if clause:
clause.insert(0, 'OR')
clause_global = clause_global.values()
clause_global = list(clause_global.values())
if clause_global:
clause_global.insert(0, 'AND')
+3 -3
View File
@@ -2,7 +2,7 @@
# this repository contains the full copyright notices and license terms.
from string import Template
import time
from itertools import izip
from sql import Literal, For
from ..model import ModelView, ModelSQL, DeactivableMixin, fields, Check
@@ -184,7 +184,7 @@ class Sequence(DeactivableMixin, ModelSQL, ModelView):
@classmethod
def create(cls, vlist):
sequences = super(Sequence, cls).create(vlist)
for sequence, values in izip(sequences, vlist):
for sequence, values in zip(sequences, vlist):
if sql_sequence and not cls._strict:
sequence.update_sql_sequence(values.get('number_next',
cls.default_number_next()))
@@ -351,7 +351,7 @@ class Sequence(DeactivableMixin, ModelSQL, ModelView):
'''
if isinstance(domain, cls):
domain = domain.id
if isinstance(domain, (int, long)):
if isinstance(domain, int):
domain = [('id', '=', domain)]
# bypass rules on sequences
+552 -552
View File
File diff suppressed because it is too large. Load diff
+23 -24
View File
@@ -1,14 +1,13 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import polib
import os
import xml.dom.minidom
from difflib import SequenceMatcher
import os
from hashlib import md5
from lxml import etree
from itertools import izip
from io import BytesIO
from lxml import etree
import polib
from sql import Column, Null, Literal
from sql.functions import Substring, Position
from sql.conditionals import Case
@@ -259,7 +258,7 @@ class Translation(ModelSQL, ModelView):
[[trans_name, 'en', 'selection', val, val_md5,
'', module_name, False, -1]]))
for field_name, field in model._fields.iteritems():
for field_name, field in model._fields.items():
trans_name = model.__name__ + ',' + field_name
update_insert_field(field, trans_name)
update_insert_help(field, trans_name)
@@ -326,7 +325,7 @@ class Translation(ModelSQL, ModelView):
where=ir_translation.id ==
trans_buttons[trans_name]['id']))
for state_name, state in wizard.states.iteritems():
for state_name, state in wizard.states.items():
if not isinstance(state, StateView):
continue
for button in state.buttons:
@@ -395,20 +394,20 @@ class Translation(ModelSQL, ModelView):
Model = pool.get('ir.model')
translations, to_fetch = {}, []
name = unicode(name)
ttype = unicode(ttype)
lang = unicode(lang)
name = str(name)
ttype = str(ttype)
lang = str(lang)
if name.split(',')[0] in ('ir.model.field', 'ir.model'):
field_name = name.split(',')[1]
with Transaction().set_context(_check_access=False):
if name.split(',')[0] == 'ir.model.field':
if field_name == 'field_description':
ttype = u'field'
ttype = 'field'
else:
ttype = u'help'
ttype = 'help'
records = ModelFields.browse(ids)
else:
ttype = u'model'
ttype = 'model'
records = Model.browse(ids)
trans_args = []
@@ -524,7 +523,7 @@ class Translation(ModelSQL, ModelView):
translations[translation.name] = translation
to_save = []
for record, value in izip(records, values):
for record, value in zip(records, values):
translation = translations.get(get_name(record))
if not translation:
translation = cls()
@@ -565,7 +564,7 @@ class Translation(ModelSQL, ModelView):
).append(translation)
to_save = []
for record, value in izip(records, values):
for record, value in zip(records, values):
translation = translations.get(record.id)
if not translation:
translation = cls()
@@ -632,11 +631,11 @@ class Translation(ModelSQL, ModelView):
to_cache = []
for name, ttype, lang, source in args:
name = unicode(name)
ttype = unicode(ttype)
lang = unicode(lang)
name = str(name)
ttype = str(ttype)
lang = str(lang)
if source is not None:
source = unicode(source)
source = str(source)
trans = cls._translation_cache.get((name, ttype, lang, source), -1)
if trans != -1:
res[(name, ttype, lang, source)] = trans
@@ -749,7 +748,7 @@ class Translation(ModelSQL, ModelView):
def translation_import(cls, lang, module, po_path):
pool = Pool()
ModelData = pool.get('ir.model.data')
if isinstance(po_path, basestring):
if isinstance(po_path, str):
po_path = [po_path]
models_data = ModelData.search([
('module', '=', module),
@@ -873,7 +872,7 @@ class Translation(ModelSQL, ModelView):
to_save.append(old_translation)
else:
translations.add(old_translation)
cls.save(filter(None, to_save))
cls.save([_f for _f in to_save if _f])
translations |= set(to_save)
if translations:
@@ -939,7 +938,7 @@ class Translation(ModelSQL, ModelView):
if pofile:
pofile.sort()
return unicode(pofile).encode('utf-8')
return str(pofile).encode('utf-8')
else:
return
@@ -1392,15 +1391,15 @@ class TranslationClean(Wizard):
except KeyError:
pass
if Model:
errors = Model._error_messages.values()
errors = list(Model._error_messages.values())
if issubclass(Model, ModelSQL):
errors += Model._sql_error_messages.values()
errors += list(Model._sql_error_messages.values())
for _, _, error in Model._sql_constraints:
errors.append(error)
if translation.src not in errors:
return True
elif Wizard:
errors = Wizard._error_messages.values()
errors = list(Wizard._error_messages.values())
if translation.src not in errors:
return True
else:
+5 -5
View File
@@ -159,7 +159,7 @@ class Trigger(DeactivableMixin, ModelSQL, ModelView):
('model.model', '=', model_name),
('on_%s' % mode, '=', True),
])
cls._get_triggers_cache.set(key, map(int, triggers))
cls._get_triggers_cache.set(key, list(map(int, triggers)))
return triggers
@staticmethod
@@ -185,7 +185,7 @@ class Trigger(DeactivableMixin, ModelSQL, ModelView):
ActionModel = pool.get(trigger.action_model.model)
cursor = Transaction().connection.cursor()
trigger_log = TriggerLog.__table__()
ids = map(int, records)
ids = list(map(int, records))
# Filter on limit_number
if trigger.limit_number:
@@ -222,12 +222,12 @@ class Trigger(DeactivableMixin, ModelSQL, ModelView):
new_ids.append(record_id)
continue
# SQLite return string for MAX
if isinstance(delay[record_id], basestring):
if isinstance(delay[record_id], str):
datepart, timepart = delay[record_id].split(" ")
year, month, day = map(int, datepart.split("-"))
timepart_full = timepart.split(".")
hours, minutes, seconds = map(int,
timepart_full[0].split(":"))
hours, minutes, seconds = map(
int, timepart_full[0].split(":"))
if len(timepart_full) == 2:
microseconds = int(timepart_full[1])
else:
+1 -1
View File
@@ -46,7 +46,7 @@ class Icon(ModelSQL, ModelView):
order=[('sequence', 'ASC'), ('id', 'ASC')])):
if icon.name not in icons:
icons[icon.name] = icon.id
return sorted((icon_id, name) for name, icon_id in icons.iteritems())
return sorted((icon_id, name) for name, icon_id in icons.items())
def get_icon(self, name):
path = os.path.join(self.module, self.path.replace('/', os.sep))
+2 -2
View File
@@ -165,7 +165,7 @@ class UIMenu(DeactivableMixin, sequence_ordered(), tree(separator=' / '),
action2keyword = {k.action.id: k for k in action_keywords}
with Transaction().set_context(active_test=False):
factions = Action.search([
('action', 'in', action2keyword.keys()),
('action', 'in', list(action2keyword.keys())),
])
for action in factions:
model = action2keyword[action.id].model
@@ -189,7 +189,7 @@ class UIMenu(DeactivableMixin, sequence_ordered(), tree(separator=' / '),
ActionKeyword.delete(action_keywords)
if not value:
return
if isinstance(value, basestring):
if isinstance(value, str):
action_type, action_id = value.split(',')
else:
action_type, action_id = value
+4 -9
View File
@@ -1,7 +1,6 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import os
import sys
import logging
import json
@@ -118,11 +117,7 @@ class View(ModelSQL, ModelView):
key = (cls.__name__, type_)
rng = cls._get_rng_cache.get(key)
if rng is None:
if sys.version_info < (3,):
filename = __file__.decode(sys.getfilesystemencoding())
else:
filename = __file__
rng_name = os.path.join(os.path.dirname(filename), type_ + '.rng')
rng_name = os.path.join(os.path.dirname(__file__), type_ + '.rng')
with open(rng_name, 'rb') as fp:
rng = etree.fromstring(fp.read())
cls._get_rng_cache.set(key, rng)
@@ -173,7 +168,7 @@ class View(ModelSQL, ModelView):
try:
value = PYSONDecoder().decode(element.get(attr))
validates.get(attr, lambda a: True)(value)
except Exception, e:
except Exception as e:
error_log = '%s: <%s %s="%s"/>' % (
e, element.get('id') or element.get('name'), attr,
element.get(attr))
@@ -298,12 +293,12 @@ class ViewTreeWidth(ModelSQL, ModelView):
records = cls.search([
('user', '=', Transaction().user),
('model', '=', model),
('field', 'in', fields.keys()),
('field', 'in', list(fields.keys())),
])
cls.delete(records)
to_create = []
for field in fields.keys():
for field in list(fields.keys()):
to_create.append({
'model': model,
'field': field,
+1 -1
View File
@@ -13,7 +13,7 @@ class dualmethod(object):
>>> class Example(object):
... @dualmethod
... def method(cls, instances):
... print len(instances)
... print(len(instances))
...
>>> Example.method([Example()])
1
+1 -1
View File
@@ -80,7 +80,7 @@ class DictSchemaMixin(object):
selection = OrderedDict(json.loads(
english_key.selection_json))
selection.update(dict(json.loads(record.selection_json)))
new_key['selection'] = selection.items()
new_key['selection'] = list(selection.items())
new_key['sorted'] = record.selection_sorted
elif record.type_ in ('float', 'numeric'):
new_key['digits'] = (16, record.digits)
+1 -1
View File
@@ -86,7 +86,7 @@ class Binary(Field):
continue
value = i[name]
if value:
if isinstance(value, unicode):
if isinstance(value, str):
value = value.encode('utf-8')
value = converter(value)
else:
+1 -4
View File
@@ -1,6 +1,5 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import sys
import warnings
from trytond.transaction import Transaction
@@ -51,9 +50,7 @@ class Char(FieldTranslate):
def sql_format(self, value):
if value is None:
return None
elif isinstance(value, str) and sys.version_info < (3,):
return unicode(value, 'utf-8')
assert isinstance(value, unicode)
assert isinstance(value, str)
return value
@property
+5 -5
View File
@@ -32,8 +32,8 @@ class Date(Field):
def sql_format(self, value):
if value is None:
return None
if isinstance(value, basestring):
year, month, day = map(int, value.split("-", 2))
if isinstance(value, str):
year, month, day = list(map(int, value.split("-", 2)))
return datetime.date(year, month, day)
if (not isinstance(value, datetime.date)
@@ -77,7 +77,7 @@ class DateTime(Field):
def sql_format(self, value):
if not value:
return None
if isinstance(value, basestring):
if isinstance(value, str):
datepart, timepart = value.split(" ")
year, month, day = map(int, datepart.split("-", 2))
hours, minutes, seconds = map(int, timepart.split(":"))
@@ -103,7 +103,7 @@ class Timestamp(Field):
def sql_format(self, value):
if value is None:
return None
if isinstance(value, basestring):
if isinstance(value, str):
datepart, timepart = value.split(" ")
year, month, day = map(int, datepart.split("-", 2))
timepart_full = timepart.split(".", 1)
@@ -130,7 +130,7 @@ class Time(DateTime):
def sql_format(self, value):
if value is None:
return None
if isinstance(value, basestring):
if isinstance(value, str):
hours, minutes, seconds = map(int, value.split(":"))
return datetime.time(hours, minutes, seconds)
if not isinstance(value, datetime.time):
+2 -2
View File
@@ -28,7 +28,7 @@ class Dict(Field):
data = value[name]
if data:
# If stored as JSON conversion is done on backend
if isinstance(data, basestring):
if isinstance(data, str):
data = json.loads(data, object_hook=JSONDecoder())
dicts[value['id']] = data
return dicts
@@ -86,4 +86,4 @@ class TranslatedDict(object):
elif self.type_ == 'values':
trans = {k['name']: dict(k['selection']) for k in keys}
return {k: v if k not in trans else trans[k].get(v, v)
for k, v in value.iteritems()}
for k, v in value.items()}
+2 -2
View File
@@ -25,13 +25,13 @@ def domain_validate(value):
def test_domain(dom):
for arg in dom:
if isinstance(arg, basestring):
if isinstance(arg, str):
if arg not in ('AND', 'OR'):
return False
elif (isinstance(arg, tuple)
or (isinstance(arg, list)
and len(arg) > 2
and ((isinstance(arg[1], basestring)
and ((isinstance(arg[1], str)
and arg[1] in OPERATORS)
or (isinstance(arg[1], PYSON)
and arg[1].types() == set([str]))))):
+2 -2
View File
@@ -8,10 +8,10 @@ def digits_validate(value):
if value:
assert isinstance(value, tuple), 'digits must be a tuple'
for i in value:
assert isinstance(i, (int, long, PYSON)), \
assert isinstance(i, (int, PYSON)), \
'digits must be tuple of integers or PYSON'
if isinstance(i, PYSON):
assert i.types().issubset(set([int, long])), \
assert i.types().issubset(set([int, int])), \
'PYSON digits must return an integer'
+4 -4
View File
@@ -87,6 +87,8 @@ class Function(Field):
with Transaction().set_context(_check_access=False):
method = getattr(Model, self.getter)
instance_method = is_instance_method(Model, self.getter)
signature = inspect.signature(method)
uses_names = 'names' in signature.parameters
def call(name):
records = Model.browse(ids)
@@ -96,13 +98,11 @@ class Function(Field):
return dict((r.id, method(r, name)) for r in records)
if isinstance(name, list):
names = name
# Test is the function works with a list of names
if 'names' in inspect.getargspec(method)[0]:
if uses_names:
return call(names)
return dict((name, call(name)) for name in names)
else:
# Test is the function works with a list of names
if 'names' in inspect.getargspec(method)[0]:
if uses_names:
name = [name]
return call(name)
+6 -6
View File
@@ -143,7 +143,7 @@ class Many2Many(Field):
for relation in relations:
origin_id = getattr(relation, self.origin).id
res[origin_id].append(getattr(relation, self.target).id)
return dict((key, tuple(value)) for key, value in res.iteritems())
return dict((key, tuple(value)) for key, value in res.items())
def set(self, Model, name, ids, values, *args):
'''
@@ -196,7 +196,7 @@ class Many2Many(Field):
target_to_delete.extend(Target.browse(target_ids))
def add(ids, target_ids):
target_ids = map(int, target_ids)
target_ids = list(map(int, target_ids))
if not target_ids:
return
existing_ids = set()
@@ -219,7 +219,7 @@ class Many2Many(Field):
})
def remove(ids, target_ids):
target_ids = map(int, target_ids)
target_ids = list(map(int, target_ids))
if not target_ids:
return
for sub_ids in grouped_slice(target_ids):
@@ -229,7 +229,7 @@ class Many2Many(Field):
]))
def copy(ids, copy_ids, default=None):
copy_ids = map(int, copy_ids)
copy_ids = list(map(int, copy_ids))
if default is None:
default = {}
@@ -367,7 +367,7 @@ class Many2Many(Field):
if operator.startswith('not'):
return ~expression
return expression
if isinstance(value, basestring):
if isinstance(value, str):
target_domain = [('rec_name', 'ilike', value)]
if self.filter:
target_domain.append(self.filter)
@@ -406,7 +406,7 @@ class Many2Many(Field):
return ~expression
return expression
else:
if isinstance(value, basestring):
if isinstance(value, str):
target_name = 'rec_name'
else:
target_name = 'id'
+3 -3
View File
@@ -101,7 +101,7 @@ class Many2One(Field):
Target = self.get_target()
if isinstance(value, dict):
value = Target(**value)
elif isinstance(value, (int, long)):
elif isinstance(value, int):
value = Target(value)
assert isinstance(value, (Target, type(None)))
super(Many2One, self).__set__(inst, value)
@@ -184,7 +184,7 @@ class Many2One(Field):
return ~expression
return expression
if isinstance(value, basestring):
if isinstance(value, str):
targets = Target.search([('rec_name', 'ilike', value)],
order=[])
ids = [t.id for t in targets]
@@ -212,7 +212,7 @@ class Many2One(Field):
return ~expression
return expression
if not isinstance(value, basestring):
if not isinstance(value, str):
return super(Many2One, self).convert_domain(domain, tables,
Model)
else:
+1 -1
View File
@@ -24,7 +24,7 @@ class Numeric(Float):
def sql_format(self, value):
if value is None:
return None
if isinstance(value, (int, long)):
if isinstance(value, int):
value = Decimal(str(value))
value = Decimal(value)
return value
+5 -5
View File
@@ -140,7 +140,7 @@ class One2Many(Field):
for target in targets:
origin_id = getattr(target, self.field).id
res[origin_id].append(target.id)
return dict((key, tuple(value)) for key, value in res.iteritems())
return dict((key, tuple(value)) for key, value in res.items())
def set(self, Model, name, ids, values, *args):
'''
@@ -189,7 +189,7 @@ class One2Many(Field):
to_delete.extend(Target.browse(target_ids))
def add(ids, target_ids):
target_ids = map(int, target_ids)
target_ids = list(map(int, target_ids))
if not target_ids:
return
targets = Target.browse(target_ids)
@@ -199,7 +199,7 @@ class One2Many(Field):
}))
def remove(ids, target_ids):
target_ids = map(int, target_ids)
target_ids = list(map(int, target_ids))
if not target_ids:
return
for sub_ids in grouped_slice(target_ids):
@@ -212,7 +212,7 @@ class One2Many(Field):
}))
def copy(ids, copy_ids, default=None):
copy_ids = map(int, copy_ids)
copy_ids = list(map(int, copy_ids))
if default is None:
default = {}
@@ -297,7 +297,7 @@ class One2Many(Field):
return ~expression
return expression
else:
if isinstance(value, basestring):
if isinstance(value, str):
target_name = 'rec_name'
else:
target_name = 'id'
+2 -2
View File
@@ -23,7 +23,7 @@ class One2One(Many2Many):
:return: a dictionary with ids as key and target id as value
'''
res = super(One2One, self).get(ids, model, name, values=values)
for i, vals in res.iteritems():
for i, vals in res.items():
res[i] = vals[0] if vals else None
return res
@@ -57,7 +57,7 @@ class One2One(Many2Many):
Target = self.get_target()
if isinstance(value, dict):
value = Target(*value)
elif isinstance(value, (int, long)):
elif isinstance(value, int):
value = Target(value)
assert isinstance(value, (Target, type(None)))
Field.__set__(self, inst, value)
+4 -4
View File
@@ -119,7 +119,7 @@ class Reference(Field, SelectionMixin):
# Check if reference ids still exist
with Transaction().set_context(active_test=False), \
Transaction().set_context(_check_access=False):
for ref_model, (ref_ids, ids) in ref_to_check.iteritems():
for ref_model, (ref_ids, ids) in ref_to_check.items():
try:
pool.get(ref_model)
except KeyError:
@@ -129,7 +129,7 @@ class Reference(Field, SelectionMixin):
refs = Ref.search([
('id', 'in', list(ref_ids)),
], order=[])
refs = map(str, refs)
refs = list(map(str, refs))
for i in ids:
if res[i] not in refs:
res[i] = None
@@ -138,7 +138,7 @@ class Reference(Field, SelectionMixin):
def __set__(self, inst, value):
from ..model import Model
if not isinstance(value, (Model, type(None))):
if isinstance(value, basestring):
if isinstance(value, str):
target, value = value.split(',')
else:
target, value = value
@@ -150,7 +150,7 @@ class Reference(Field, SelectionMixin):
super(Reference, self).__set__(inst, value)
def sql_format(self, value):
if not isinstance(value, (basestring, Query, Expression)):
if not isinstance(value, (str, Query, Expression)):
try:
value = '%s,%s' % tuple(value)
except TypeError:
+1 -1
View File
@@ -8,7 +8,7 @@ class MatchMixin(object):
'''Match on pattern
pattern is a dictionary with model field as key
and matching value as value'''
for field, pattern_value in pattern.iteritems():
for field, pattern_value in pattern.items():
value = getattr(self, field)
if not match_none and value is None:
continue
+10 -10
View File
@@ -66,7 +66,7 @@ class Model(WarningErrorMixin, URLMixin, PoolBase):
# Set _defaults
cls._defaults = {}
fields_names = cls._fields.keys()
fields_names = list(cls._fields.keys())
for field_name in fields_names:
default_method = getattr(cls, 'default_%s' % field_name, False)
if isinstance(default_method, collections.Callable):
@@ -78,7 +78,7 @@ class Model(WarningErrorMixin, URLMixin, PoolBase):
% (cls.__name__, k,)
# Set name to fields
for name, field in cls._fields.iteritems():
for name, field in cls._fields.items():
if field.name is None:
field.name = name
else:
@@ -148,7 +148,7 @@ class Model(WarningErrorMixin, URLMixin, PoolBase):
value[field_name]).rec_name
if not with_rec_name:
for field in value.keys():
for field in list(value.keys()):
if field.endswith('.rec_name'):
del value[field]
return value
@@ -306,7 +306,7 @@ class Model(WarningErrorMixin, URLMixin, PoolBase):
if res[field]['type'] == 'many2one':
target = cls._fields[field].get_target()
relation_fields = []
for target_name, target_field in target._fields.iteritems():
for target_name, target_field in target._fields.items():
if (target_field._type == 'one2many'
and target_field.model_name == cls.__name__
and target_field.field == field):
@@ -336,7 +336,7 @@ class Model(WarningErrorMixin, URLMixin, PoolBase):
if attr in res[field]:
res[field][attr] = encoder.encode(res[field][attr])
for i in res.keys():
for i in list(res.keys()):
# filter out fields which aren't in the fields_names list
if fields_names:
if i not in fields_names:
@@ -356,7 +356,7 @@ class Model(WarningErrorMixin, URLMixin, PoolBase):
if kwargs:
self._values = {}
parent_values = {}
for name, value in kwargs.iteritems():
for name, value in kwargs.items():
if not name.startswith('_parent_'):
setattr(self, name, value)
else:
@@ -374,7 +374,7 @@ class Model(WarningErrorMixin, URLMixin, PoolBase):
else:
setattr(record, parent_name, {field: value})
for name, value in parent_values.iteritems():
for name, value in parent_values.items():
set_parent_value(self, name, value)
self._init_values = self._values.copy()
else:
@@ -398,7 +398,7 @@ class Model(WarningErrorMixin, URLMixin, PoolBase):
return '%s,%s' % (self.__name__, self.id)
def __unicode__(self):
return u'%s,%s' % (self.__name__, self.id)
return '%s,%s' % (self.__name__, self.id)
def __repr__(self):
if self.id is None or self.id < 0:
@@ -425,7 +425,7 @@ class Model(WarningErrorMixin, URLMixin, PoolBase):
def __hash__(self):
return hash((self.__name__, self.id))
def __nonzero__(self):
def __bool__(self):
return True
@property
@@ -439,7 +439,7 @@ class Model(WarningErrorMixin, URLMixin, PoolBase):
"""
values = {}
if self._values:
for fname, value in self._values.iteritems():
for fname, value in self._values.items():
field = self._fields[fname]
if field._type in ('many2one', 'one2one', 'reference'):
if value:
+5 -5
View File
@@ -32,14 +32,14 @@ class ModelSingleton(ModelStorage):
singleton = cls.get_singleton()
if not singleton:
if not fields_names:
fields_names = cls._fields.keys()
fields_names = list(cls._fields.keys())
fname_no_rec_name = [f for f in fields_names if '.' not in f]
res = cls.default_get(fname_no_rec_name,
with_rec_name=len(fname_no_rec_name) != len(fields_names))
for field_name in fields_names:
if field_name not in res:
res[field_name] = None
for field_name in res.keys():
for field_name in list(res.keys()):
if field_name not in fields_names:
del res[field_name]
res['id'] = ids[0]
@@ -65,7 +65,7 @@ class ModelSingleton(ModelStorage):
if local_cache:
local_cache.clear()
# Clean transaction cache of all ids
for cache in Transaction().cache.itervalues():
for cache in Transaction().cache.values():
if cls.__name__ in cache:
cache[cls.__name__].clear()
@@ -75,7 +75,7 @@ class ModelSingleton(ModelStorage):
if singleton:
super(ModelSingleton, cls).delete([singleton])
# Clean transaction cache of all ids
for cache in Transaction().cache.itervalues():
for cache in Transaction().cache.values():
if cls.__name__ in cache:
cache[cls.__name__].clear()
@@ -110,6 +110,6 @@ class ModelSingleton(ModelStorage):
if cls._fields[field]._type in ('many2one',):
fields_names.append(field + '.rec_name')
default, = cls.read([singleton.id], fields_names=fields_names)
for field in (x for x in default.keys() if x not in fields_names):
for field in (x for x in list(default.keys()) if x not in fields_names):
del default[field]
return default
+42 -42
View File
@@ -1,7 +1,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime
from itertools import islice, izip, chain, ifilter
from itertools import islice, chain
from collections import OrderedDict
from functools import wraps
@@ -208,7 +208,7 @@ class ModelSQL(ModelStorage):
history_table = TableHandler(cls, module_name, history=True)
history_table.index_action('id', action='add')
for field_name, field in cls._fields.iteritems():
for field_name, field in cls._fields.items():
if field_name == 'id':
continue
sql_type = field.sql_type()
@@ -266,7 +266,7 @@ class ModelSQL(ModelStorage):
table.not_null_action(
field_name, action=required and 'add' or 'remove')
for field_name, field in cls._fields.iteritems():
for field_name, field in cls._fields.items():
if isinstance(field, fields.Many2One) \
and field.model_name == cls.__name__ \
and field.left and field.right:
@@ -292,7 +292,7 @@ class ModelSQL(ModelStorage):
cursor.execute(
*history_table.select(history_table.id, limit=1))
if not cursor.fetchone():
columns = [n for n, f in cls._fields.iteritems()
columns = [n for n, f in cls._fields.items()
if f.sql_type()]
cursor.execute(*history_table.insert(
[Column(history_table, c) for c in columns],
@@ -306,7 +306,7 @@ class ModelSQL(ModelStorage):
TableHandler = backend.get('TableHandler')
if cls._history:
history_table = TableHandler(cls, history=True)
for field_name, field in cls._fields.iteritems():
for field_name, field in cls._fields.items():
if not field.sql_type():
continue
history_table.add_column(field_name, field._sql_type)
@@ -314,7 +314,7 @@ class ModelSQL(ModelStorage):
@classmethod
def _get_error_messages(cls):
res = super(ModelSQL, cls)._get_error_messages()
res += cls._sql_error_messages.values()
res += list(cls._sql_error_messages.values())
for _, _, error in cls._sql_constraints:
res.append(error)
return res
@@ -325,7 +325,7 @@ class ModelSQL(ModelStorage):
pool = Pool()
TableHandler = backend.get('TableHandler')
if field_names is None:
field_names = cls._fields.keys()
field_names = list(cls._fields.keys())
if transaction is None:
transaction = Transaction()
for field_name in field_names:
@@ -356,10 +356,10 @@ class ModelSQL(ModelStorage):
cls.raise_user_error('foreign_model_missing',
error_args=error_args)
for name, _, error in cls._sql_constraints:
if TableHandler.convert_name(name) in unicode(exception):
if TableHandler.convert_name(name) in str(exception):
cls.raise_user_error(error)
for name, error in cls._sql_error_messages.iteritems():
if TableHandler.convert_name(name) in unicode(exception):
for name, error in cls._sql_error_messages.items():
if TableHandler.convert_name(name) in str(exception):
cls.raise_user_error(error)
@classmethod
@@ -387,7 +387,7 @@ class ModelSQL(ModelStorage):
revisions = list(chain(*revisions))
revisions.sort(reverse=True)
# SQLite uses char for COALESCE
if revisions and isinstance(revisions[0][0], basestring):
if revisions and isinstance(revisions[0][0], str):
strptime = datetime.datetime.strptime
format_ = '%Y-%m-%d %H:%M:%S.%f'
revisions = [(strptime(timestamp, format_), id_, name)
@@ -413,7 +413,7 @@ class ModelSQL(ModelStorage):
'write_uid': cls.write_uid,
'write_date': cls.write_date,
}
for fname, field in sorted(fields.iteritems()):
for fname, field in sorted(fields.items()):
if not field.sql_type():
continue
columns.append(Column(table, fname))
@@ -443,7 +443,7 @@ class ModelSQL(ModelStorage):
history = cls.__table_history__()
columns = []
hcolumns = []
fnames = sorted(n for n, f in cls._fields.iteritems()
fnames = sorted(n for n, f in cls._fields.items()
if f.sql_type())
for fname in fnames:
columns.append(Column(table, fname))
@@ -575,7 +575,7 @@ class ModelSQL(ModelStorage):
insert_values = [transaction.user, CurrentTimestamp()]
# Insert record
for fname, value in values.iteritems():
for fname, value in values.items():
field = cls._fields[fname]
if not hasattr(field, 'set'):
insert_columns.append(Column(table, fname))
@@ -599,7 +599,7 @@ class ModelSQL(ModelStorage):
[insert_values]))
id_new = transaction.database.lastid(cursor)
new_ids.append(id_new)
except DatabaseIntegrityError, exception:
except DatabaseIntegrityError as exception:
transaction = Transaction()
with Transaction().new_transaction(), \
Transaction().set_context(_check_access=False):
@@ -612,8 +612,8 @@ class ModelSQL(ModelStorage):
translation_values = {}
fields_to_set = {}
for values, new_id in izip(vlist, new_ids):
for fname, value in values.iteritems():
for values, new_id in zip(vlist, new_ids):
for fname, value in values.items():
field = cls._fields[fname]
if (getattr(field, 'translate', False)
and not hasattr(field, 'set')):
@@ -630,9 +630,9 @@ class ModelSQL(ModelStorage):
args.extend(([new_id], value))
if translation_values:
for name, translations in translation_values.iteritems():
for name, translations in translation_values.items():
Translation.set_ids(name, 'model', Transaction().language,
translations.keys(), translations.values())
list(translations.keys()), list(translations.values()))
for fname in sorted(fields_to_set, key=cls.index_set_field):
fargs = fields_to_set[fname]
@@ -641,7 +641,7 @@ class ModelSQL(ModelStorage):
cls._insert_history(new_ids)
field_names = cls._fields.keys()
field_names = list(cls._fields.keys())
cls._update_mptt(field_names, [new_ids] * len(field_names))
cls.__check_domain_rule(new_ids, 'create')
@@ -660,7 +660,7 @@ class ModelSQL(ModelStorage):
ModelAccess = pool.get('ir.model.access')
if not fields_names:
fields_names = []
for field_name in cls._fields.keys():
for field_name in list(cls._fields.keys()):
if ModelAccess.check_relation(cls.__name__, field_name,
mode='read'):
fields_names.append(field_name)
@@ -706,7 +706,7 @@ class ModelSQL(ModelStorage):
history_limit = 1
columns = []
for f in fields_names + fields_related.keys() + datetime_fields:
for f in fields_names + list(fields_related.keys()) + datetime_fields:
field = cls._fields.get(f)
if field and field.sql_type():
columns.append(field.sql_column(table).as_(f))
@@ -773,7 +773,7 @@ class ModelSQL(ModelStorage):
# all fields for which there is a get attribute
getter_fields = [f for f in
fields_names + fields_related.keys() + datetime_fields
fields_names + list(fields_related.keys()) + datetime_fields
if f in cls._fields and hasattr(cls._fields[f], 'get')]
if getter_fields and cachable_fields:
@@ -828,7 +828,7 @@ class ModelSQL(ModelStorage):
to_del = set()
fields_related2values = {}
for fname in fields_related.keys() + datetime_fields:
for fname in list(fields_related.keys()) + datetime_fields:
if fname not in fields_names:
to_del.add(fname)
if fname not in cls._fields:
@@ -947,7 +947,7 @@ class ModelSQL(ModelStorage):
columns = [table.write_uid, table.write_date]
update_values = [transaction.user, CurrentTimestamp()]
store_translation = Transaction().language == Config.get_language()
for fname, value in values.iteritems():
for fname, value in values.items():
field = cls._fields[fname]
if not hasattr(field, 'set'):
if (not getattr(field, 'translate', False)
@@ -960,16 +960,16 @@ class ModelSQL(ModelStorage):
try:
cursor.execute(*table.update(columns, update_values,
where=red_sql))
except DatabaseIntegrityError, exception:
except DatabaseIntegrityError as exception:
transaction = Transaction()
with Transaction().new_transaction(), \
Transaction().set_context(_check_access=False):
cls.__raise_integrity_error(
exception, values, values.keys(),
exception, values, list(values.keys()),
transaction=transaction)
raise
for fname, value in values.iteritems():
for fname, value in values.items():
field = cls._fields[fname]
if (getattr(field, 'translate', False)
and not hasattr(field, 'set')):
@@ -979,7 +979,7 @@ class ModelSQL(ModelStorage):
if hasattr(field, 'set'):
fields_to_set.setdefault(fname, []).extend((ids, value))
field_names = values.keys()
field_names = list(values.keys())
cls._update_mptt(field_names, [ids] * len(field_names), values)
all_field_names |= set(field_names)
@@ -1004,7 +1004,7 @@ class ModelSQL(ModelStorage):
cursor = transaction.connection.cursor()
pool = Pool()
Translation = pool.get('ir.translation')
ids = map(int, records)
ids = list(map(int, records))
if not ids:
return
@@ -1022,7 +1022,7 @@ class ModelSQL(ModelStorage):
has_translation = False
tree_ids = {}
for fname, field in cls._fields.iteritems():
for fname, field in cls._fields.items():
if (isinstance(field, fields.Many2One)
and field.model_name == cls.__name__
and field.left and field.right):
@@ -1043,7 +1043,7 @@ class ModelSQL(ModelStorage):
continue
if not issubclass(model, ModelStorage):
continue
for field_name, field in model._fields.iteritems():
for field_name, field in model._fields.items():
if (isinstance(field, fields.Many2One)
and field.model_name == cls.__name__):
if field.ondelete == 'CASCADE':
@@ -1072,7 +1072,7 @@ class ModelSQL(ModelStorage):
records = Model.search([(field_name, 'in', sub_ids)])
return records
for sub_ids, sub_records in izip(
for sub_ids, sub_records in zip(
grouped_slice(ids), grouped_slice(records)):
sub_ids = list(sub_ids)
red_sql = reduce_ids(table.id, sub_ids)
@@ -1111,7 +1111,7 @@ class ModelSQL(ModelStorage):
try:
cursor.execute(*table.delete(where=red_sql))
except DatabaseIntegrityError, exception:
except DatabaseIntegrityError as exception:
transaction = Transaction()
with Transaction().new_transaction():
cls.__raise_integrity_error(
@@ -1123,7 +1123,7 @@ class ModelSQL(ModelStorage):
cls._insert_history(ids, deleted=True)
cls._update_mptt(tree_ids.keys(), tree_ids.values())
cls._update_mptt(list(tree_ids.keys()), list(tree_ids.values()))
@classmethod
def __check_domain_rule(cls, ids, mode, nodomain=None):
@@ -1215,7 +1215,7 @@ class ModelSQL(ModelStorage):
columns.append(Column(main_table, '__id').as_('__id'))
if not query:
columns += [f.sql_column(main_table).as_(n)
for n, f in cls._fields.iteritems()
for n, f in cls._fields.items()
if not hasattr(f, 'get')
and n != 'id'
and not getattr(f, 'translate', False)
@@ -1267,14 +1267,14 @@ class ModelSQL(ModelStorage):
<= transaction.context['_datetime'])))
for deleted_id, delete_date in cursor.fetchall():
history_date, _ = ids_history[deleted_id]
if isinstance(history_date, basestring):
if isinstance(history_date, str):
strptime = datetime.datetime.strptime
format_ = '%Y-%m-%d %H:%M:%S.%f'
history_date = strptime(history_date, format_)
if history_date <= delete_date:
to_delete.add(deleted_id)
return ifilter(lambda r: history_key(r) == ids_history[r['id']]
return filter(lambda r: history_key(r) == ids_history[r['id']]
and r['id'] not in to_delete, rows)
# Can not cache the history value if we are not sure to have fetch all
@@ -1287,7 +1287,7 @@ class ModelSQL(ModelStorage):
if data['id'] in delete_records:
continue
if keys is None:
keys = data.keys()
keys = list(data.keys())
for k in keys[:]:
if k in ('_timestamp', '_datetime', '__id'):
keys.remove(k)
@@ -1334,7 +1334,7 @@ class ModelSQL(ModelStorage):
def is_leaf(expression):
return (isinstance(expression, (list, tuple))
and len(expression) > 2
and isinstance(expression[1], basestring)
and isinstance(expression[1], str)
and expression[1] in OPERATORS) # TODO remove OPERATORS test
def convert(domain):
@@ -1489,7 +1489,7 @@ class ModelSQL(ModelStorage):
lock = database.lock
cursor = transaction.connection.cursor()
# Works only for a single transaction
ids = map(int, records)
ids = list(map(int, records))
for _, sql, error in cls._sql_constraints:
if has_constraint(sql):
continue
@@ -1537,7 +1537,7 @@ def convert_from(table, tables):
table = table.join(right, 'LEFT', condition)
else:
table = right
for k, sub_tables in tables.iteritems():
for k, sub_tables in tables.items():
if k is None:
continue
table = convert_from(table, sub_tables)
+55 -55
View File
@@ -7,7 +7,7 @@ import csv
import warnings
from decimal import Decimal
from itertools import islice, ifilter, chain, izip
from itertools import islice, chain
from functools import reduce, wraps
from operator import itemgetter
from collections import defaultdict
@@ -60,14 +60,14 @@ class ModelStorage(Model):
if issubclass(cls, ModelView):
cls.__rpc__.update({
'create': RPC(readonly=False,
result=lambda r: map(int, r)),
result=lambda r: list(map(int, r))),
'read': RPC(),
'write': RPC(readonly=False,
instantiate=slice(0, None, 2)),
'delete': RPC(readonly=False, instantiate=0),
'copy': RPC(readonly=False, instantiate=0, unique=False,
result=lambda r: map(int, r)),
'search': RPC(result=lambda r: map(int, r)),
result=lambda r: list(map(int, r))),
'search': RPC(result=lambda r: list(map(int, r))),
'search_count': RPC(),
'search_read': RPC(),
'export_data': RPC(instantiate=0, unique=False),
@@ -96,7 +96,7 @@ class ModelStorage(Model):
ModelAccess.check(cls.__name__, 'create')
all_fields = list(set(chain(*(v.iterkeys() for v in vlist))))
all_fields = list(set(chain(*(iter(v.keys()) for v in vlist))))
ModelFieldAccess.check(cls.__name__, all_fields, 'write')
# Increase transaction counter
@@ -160,7 +160,7 @@ class ModelStorage(Model):
cls.raise_user_error('write_xml_record',
error_description='xml_record_desc')
all_records += records
all_fields.update(values.iterkeys())
all_fields.update(values.keys())
ModelAccess.check(cls.__name__, 'write')
ModelFieldAccess.check(cls.__name__, all_fields, 'write')
@@ -175,7 +175,7 @@ class ModelStorage(Model):
local_cache.clear()
# Clean transaction cache
for cache in Transaction().cache.itervalues():
for cache in Transaction().cache.values():
if cls.__name__ in cache:
for record in all_records:
if record.id in cache[cls.__name__]:
@@ -206,7 +206,7 @@ class ModelStorage(Model):
eligibles is a dictionary of the lists of eligible records by triggers
'''
Trigger = Pool().get('ir.trigger')
for trigger, records in eligibles.iteritems():
for trigger, records in eligibles.items():
triggered = []
for record in records:
if Trigger.eval(trigger, record):
@@ -235,8 +235,8 @@ class ModelStorage(Model):
Transaction().counter += 1
# Clean transaction cache
for cache in Transaction().cache.values():
for cache in (cache, cache.get('_language_cache', {}).values()):
for cache in list(Transaction().cache.values()):
for cache in (cache, list(cache.get('_language_cache', {}).values())):
if cls.__name__ in cache:
for record in records:
if record.id in cache[cls.__name__]:
@@ -319,17 +319,17 @@ class ModelStorage(Model):
# Reset MPTT field to the default value
mptt = set()
for field in cls._fields.itervalues():
for field in cls._fields.values():
if (isinstance(field, fields.Many2One)
and field.model_name == cls.__name__
and field.left and field.right):
mptt.add(field.left)
mptt.add(field.right)
fields_names = [n for n, f in cls._fields.iteritems()
fields_names = [n for n, f in cls._fields.items()
if (not isinstance(f, fields.Function)
or isinstance(f, fields.MultiValue))
and n not in mptt]
ids = map(int, records)
ids = list(map(int, records))
datas = cls.read(ids, fields_names=fields_names)
datas = dict((d['id'], d) for d in datas)
field_defs = cls.fields_get(fields_names=fields_names)
@@ -338,10 +338,10 @@ class ModelStorage(Model):
data = convert_data(field_defs, datas[id])
to_create.append(data)
new_records = cls.create(to_create)
id2new_record = dict(izip(ids, new_records))
id2new_record = dict(zip(ids, new_records))
fields_translate = {}
for field_name, field in field_defs.iteritems():
for field_name, field in field_defs.items():
if field_name in cls._fields and \
getattr(cls._fields[field_name], 'translate', False):
fields_translate[field_name] = field
@@ -351,13 +351,13 @@ class ModelStorage(Model):
('translatable', '=', True),
])
if langs:
fields_names = list(fields_translate.keys()) + ['id']
for lang in langs:
# Prevent fuzzing translations when copying as the terms
# should be the same.
with Transaction().set_context(language=lang.code,
fuzzy_translation=False):
datas = cls.read(ids,
fields_names=fields_translate.keys() + ['id'])
datas = cls.read(ids, fields_names=fields_names)
to_write = []
for data in datas:
to_write.append([id2new_record[data['id']]])
@@ -395,10 +395,10 @@ class ModelStorage(Model):
records = cls.search(domain, offset=offset, limit=limit, order=order)
if not fields_names:
fields_names = cls._fields.keys()
fields_names = list(cls._fields.keys())
if 'id' not in fields_names:
fields_names.append('id')
rows = cls.read(map(int, records), fields_names)
rows = cls.read(list(map(int, records)), fields_names)
index = {r.id: i for i, r in enumerate(records)}
rows.sort(key=lambda r: index[r['id']])
return rows
@@ -430,9 +430,9 @@ class ModelStorage(Model):
domain[i] = process(domain[i])
i += 1
if not active_found:
if (domain and ((isinstance(domain[0], basestring)
if (domain and ((isinstance(domain[0], str)
and domain[0] == 'AND')
or (not isinstance(domain[0], basestring)))):
or (not isinstance(domain[0], str)))):
domain.append(('active', '=', True))
else:
domain = ['AND', domain, ('active', '=', True)]
@@ -447,7 +447,7 @@ class ModelStorage(Model):
rec_name = self._rec_name
if rec_name not in self._fields:
rec_name = 'id'
return unicode(getattr(self, rec_name))
return str(getattr(self, rec_name))
@classmethod
def search_rec_name(cls, name, clause):
@@ -476,7 +476,7 @@ class ModelStorage(Model):
Return a list of instance for the ids
'''
transaction = Transaction()
ids = map(int, ids)
ids = list(map(int, ids))
local_cache = LRUDictTransaction(cache_size())
transaction_cache = transaction.get_cache()
return [cls(x, _ids=ids,
@@ -533,7 +533,7 @@ class ModelStorage(Model):
child_lines = ModelStorage.__export_row(child_record,
child_fields_names)
if first:
for child_fpos in xrange(len(fields_names)):
for child_fpos in range(len(fields_names)):
if child_lines and child_lines[0][child_fpos]:
data[child_fpos] = \
child_lines[0][child_fpos]
@@ -595,8 +595,8 @@ class ModelStorage(Model):
return None
res = []
Relation = pool.get(relation)
for word in csv.reader(value.splitlines(), delimiter=',',
quoting=csv.QUOTE_NONE, escapechar='\\').next():
for word in next(csv.reader(value.splitlines(), delimiter=',',
quoting=csv.QUOTE_NONE, escapechar='\\')):
res2 = Relation.search([
('rec_name', '=', word),
], limit=2)
@@ -644,8 +644,8 @@ class ModelStorage(Model):
relation = None
ftype = fields_def[field[-1][:-3]]['type']
if ftype == 'many2many':
value = csv.reader(value.splitlines(), delimiter=',',
quoting=csv.QUOTE_NONE, escapechar='\\').next()
value = next(csv.reader(value.splitlines(), delimiter=',',
quoting=csv.QUOTE_NONE, escapechar='\\'))
elif ftype == 'reference':
try:
relation, value = value.split(',', 1)
@@ -739,7 +739,7 @@ class ModelStorage(Model):
(newrow, max2, _) = res
nbrmax = max(nbrmax, max2)
reduce(lambda x, y: x and y, newrow)
row[field] = (reduce(lambda x, y: x or y, newrow.values()) and
row[field] = (reduce(lambda x, y: x or y, list(newrow.values())) and
[('create', [newrow])]) or []
i = max2
while (position + i) < len(data):
@@ -754,12 +754,12 @@ class ModelStorage(Model):
(newrow, max2, _) = \
process_lines(data, prefix + [field], newfd,
position + i)
if reduce(lambda x, y: x or y, newrow.values()):
if reduce(lambda x, y: x or y, list(newrow.values())):
row[field].append(('create', [newrow]))
i += max2
nbrmax = max(nbrmax, i)
if prefix_len == 0:
for i in xrange(max(nbrmax, 1)):
for i in range(max(nbrmax, 1)):
data.pop(0)
return (row, nbrmax, translate)
@@ -781,8 +781,8 @@ class ModelStorage(Model):
for language in languages:
translated = [t.get(language, {}) for t in translations]
with Transaction().set_context(language=language):
cls.write(*chain(*ifilter(itemgetter(1),
izip(([r] for r in new_records), translated))))
cls.write(*chain(*filter(itemgetter(1),
zip(([r] for r in new_records), translated))))
return len(new_records)
@classmethod
@@ -805,7 +805,7 @@ class ModelStorage(Model):
with Transaction().set_context(_check_access=False):
models_data = ModelData.search([
('model', '=', cls.__name__),
('db_id', 'in', map(int, records)),
('db_id', 'in', list(map(int, records))),
])
if not models_data:
return True
@@ -815,7 +815,7 @@ class ModelStorage(Model):
if not model_data.values or model_data.noupdate:
continue
xml_values = ModelData.load_values(model_data.values)
for key, val in values.iteritems():
for key, val in values.items():
if key in xml_values and val != xml_values[key]:
return False
return True
@@ -885,7 +885,7 @@ class ModelStorage(Model):
if is_pyson(i):
return True
if isinstance(test, dict):
for key, value in test.items():
for key, value in list(test.items()):
if isinstance(value, PYSON):
return True
if isinstance(value, (list, tuple, dict)):
@@ -923,7 +923,7 @@ class ModelStorage(Model):
in_max = Transaction().database.IN_MAX
count = in_max // 10
new_domains = {}
for sub_domains in grouped_slice(domains.keys(), count):
for sub_domains in grouped_slice(list(domains.keys()), count):
grouped_domain = ['OR']
grouped_records = []
for d in sub_domains:
@@ -940,7 +940,7 @@ class ModelStorage(Model):
else:
domains[freeze(field.domain)].extend(records)
for domain, sub_records in domains.iteritems():
for domain, sub_records in domains.items():
validate_relation_domain(field, sub_records, Relation, domain)
def relation_domain(field, records):
@@ -971,11 +971,11 @@ class ModelStorage(Model):
error_args=cls._get_error_args(field.name))
field_names = set(field_names or [])
function_fields = {name for name, field in cls._fields.iteritems()
function_fields = {name for name, field in cls._fields.items()
if isinstance(field, fields.Function)}
ctx_pref['active_test'] = False
with Transaction().set_context(ctx_pref):
for field_name, field in cls._fields.iteritems():
for field_name, field in cls._fields.items():
depends = set(field.depends)
if (field_names
and field_name not in field_names
@@ -989,7 +989,7 @@ class ModelStorage(Model):
def required_test(value, field_name, field):
if (isinstance(value, (type(None), type(False), list,
tuple, basestring, dict))
tuple, str, dict))
and not value):
cls.raise_user_error('required_validation_record',
error_args=cls._get_error_args(field_name))
@@ -1244,8 +1244,8 @@ class ModelStorage(Model):
FieldAccess = Pool().get('ir.model.field.access')
fread_accesses = {}
fread_accesses.update(FieldAccess.check(self.__name__,
self._fields.keys(), 'read', access=True))
to_remove = set(x for x, y in fread_accesses.iteritems()
list(self._fields.keys()), 'read', access=True))
to_remove = set(x for x, y in fread_accesses.items()
if not y and x != name)
threshold = config.getint('cache', 'field')
@@ -1264,20 +1264,20 @@ class ModelStorage(Model):
fname, field = item
return fname in self._fields
ifields = ifilter(to_load,
ifilter(not_cached,
self._fields.iteritems()))
ifields = filter(to_load,
filter(not_cached,
iter(self._fields.items())))
ifields = islice(ifields, 0, threshold)
ffields.update(ifields)
# add datetime_field
for field in ffields.values():
for field in list(ffields.values()):
if hasattr(field, 'datetime_field') and field.datetime_field:
datetime_field = self._fields[field.datetime_field]
ffields[field.datetime_field] = datetime_field
# add depends of field with context
for field in ffields.values():
for field in list(ffields.values()):
if field.context:
eval_fields = fields.get_eval_fields(field.context)
for context_field_name in eval_fields:
@@ -1300,7 +1300,7 @@ class ModelStorage(Model):
index = self._ids.index(self.id)
ids = chain(islice(self._ids, index, None),
islice(self._ids, 0, max(index - 1, 0)))
ids = islice(unique(ifilter(filter_, ids)),
ids = islice(unique(filter(filter_, ids)),
self._transaction.database.IN_MAX)
def instantiate(field, value, data):
@@ -1367,10 +1367,10 @@ class ModelStorage(Model):
for i in ids
if i in self._cache and name in self._cache[i]]
else:
read_data = self.read(list(ids), ffields.keys())
read_data = self.read(list(ids), list(ffields.keys()))
# create browse records for 'remote' models
for data in read_data:
for fname, field in ffields.iteritems():
for fname, field in ffields.items():
fvalue = data[fname]
if field._type in ('many2one', 'one2one', 'one2many',
'many2many', 'reference'):
@@ -1399,7 +1399,7 @@ class ModelStorage(Model):
values = {}
if not self._values:
return values
for fname, value in self._values.iteritems():
for fname, value in self._values.items():
field = self._fields[fname]
if field._type in ('many2one', 'one2one', 'reference'):
if value:
@@ -1483,7 +1483,7 @@ class ModelStorage(Model):
transaction.set_context(context):
if to_create:
news = cls.create([save_values[r] for r in to_create])
for record, new in izip(to_create, news):
for record, new in zip(to_create, news):
record._ids.remove(record.id)
record._id = new.id
record._ids.append(record.id)
@@ -1527,7 +1527,7 @@ class EvalEnvironment(dict):
def __getattr__(self, item):
try:
return self.__getitem__(item)
except KeyError, exception:
except KeyError as exception:
raise AttributeError(*exception.args)
def get(self, item, default=None):
@@ -1537,5 +1537,5 @@ class EvalEnvironment(dict):
pass
return super(EvalEnvironment, self).get(item, default)
def __nonzero__(self):
def __bool__(self):
return bool(self._record)
+15 -17
View File
@@ -147,13 +147,13 @@ class ModelView(Model):
if parent_value:
methods[attr][name] |= parent_value
for name, method in callables.iteritems():
for name, method in callables.items():
get_callable_attributes(name, method)
def setup_field(field_name, field, attribute):
if attribute == 'selection_change_with':
if isinstance(
getattr(field, 'selection', None), basestring):
getattr(field, 'selection', None), str):
function_name = field.selection
else:
return
@@ -184,7 +184,7 @@ class ModelView(Model):
# Decorate on_change to always return self
setattr(cls, function_name, on_change(function))
for name, field in fields_.iteritems():
for name, field in fields_.items():
for attribute in [
'on_change',
'on_change_with',
@@ -198,7 +198,7 @@ class ModelView(Model):
super(ModelView, cls).__post_setup__()
# Update __rpc__
for field_name, field in cls._fields.iteritems():
for field_name, field in cls._fields.items():
field.set_rpc(cls)
for button in cls._buttons:
@@ -243,7 +243,7 @@ class ModelView(Model):
],
]
views = View.search(domain)
views = filter(lambda v: v.rng_type == view_type, views)
views = [v for v in views if v.rng_type == view_type]
if views:
view = views[0]
if view:
@@ -391,16 +391,16 @@ class ModelView(Model):
# Find field without read access
fread_accesses = FieldAccess.check(cls.__name__,
cls._fields.keys(), 'read', access=True)
fields_to_remove = list(x for x, y in fread_accesses.iteritems()
list(cls._fields.keys()), 'read', access=True)
fields_to_remove = list(x for x, y in fread_accesses.items()
if not y)
# Find relation field without read access
for name, field in cls._fields.iteritems():
for name, field in cls._fields.items():
if not ModelAccess.check_relation(cls.__name__, name, mode='read'):
fields_to_remove.append(name)
for name, field in cls._fields.iteritems():
for name, field in cls._fields.items():
for field_to_remove in fields_to_remove:
if field_to_remove in field.depends:
fields_to_remove.append(name)
@@ -450,7 +450,7 @@ class ModelView(Model):
if hasattr(field, 'field'):
fields_def.setdefault(field.field, {'name': field.field})
for field_name in fields_def.keys():
for field_name in list(fields_def.keys()):
if field_name in cls._fields:
field = cls._fields[field_name]
else:
@@ -460,7 +460,7 @@ class ModelView(Model):
arch = etree.tostring(
tree, encoding='utf-8', pretty_print=False).decode('utf-8')
fields2 = cls.fields_get(fields_def.keys())
fields2 = cls.fields_get(list(fields_def.keys()))
for field in fields_def:
if field in fields2:
fields2[field].update(fields_def[field])
@@ -553,7 +553,7 @@ class ModelView(Model):
groups = set(User.get_groups())
button_attr = Button.get_view_attributes(
cls.__name__, button_name)
for attr, value in button_attr.iteritems():
for attr, value in button_attr.items():
if not element.get(attr):
element.set(attr, value or '')
button_groups = Button.get_groups(cls.__name__, button_name)
@@ -637,10 +637,8 @@ class ModelView(Model):
if button_rules:
clicks = ButtonClick.register(
cls.__name__, func.__name__, records)
records = filter(
lambda r: all(br.test(r, clicks.get(r.id, []))
for br in button_rules),
records)
records = [r for r in records if all(br.test(r, clicks.get(r.id, []))
for br in button_rules)]
# Reset click after filtering in case the button also has rules
names = Button.get_reset(cls.__name__, func.__name__)
if names:
@@ -711,7 +709,7 @@ class ModelView(Model):
init_values = self._init_values or {}
if not self._values:
return changed
for fname, value in self._values.iteritems():
for fname, value in self._values.items():
field = self._fields[fname]
# Always test key presence in case value is None
if (fname in init_values
+3 -3
View File
@@ -17,7 +17,7 @@ class MultiValueMixin(object):
def multivalue_records(self, field):
Value = self.multivalue_model(field)
for fname, field in self._fields.iteritems():
for fname, field in self._fields.items():
if (field._type == 'one2many'
and field.model_name == Value.__name__):
return getattr(self, fname)
@@ -25,7 +25,7 @@ class MultiValueMixin(object):
def multivalue_record(self, field, **pattern):
Value = self.multivalue_model(field)
for fname, field in Value._fields.iteritems():
for fname, field in Value._fields.items():
if (field._type == 'many2one'
and field.model_name == self.__name__):
pattern = pattern.copy()
@@ -92,4 +92,4 @@ class ValueMixin(MatchMixin):
def filter_pattern(pattern, Value):
return {f: v for f, v in pattern.iteritems() if f in Value._fields}
return {f: v for f, v in pattern.items() if f in Value._fields}
+2 -2
View File
@@ -30,7 +30,7 @@ def tree(parent='parent', name='name', separator=None):
@classmethod
def search_rec_name(cls, _, clause):
if isinstance(clause[2], basestring):
if isinstance(clause[2], str):
values = list(reversed(clause[2].split(separator)))
else:
values = [[]]
@@ -60,7 +60,7 @@ def tree(parent='parent', name='name', separator=None):
domain.append((top_parent, operator, None))
if (clause[1].endswith('like')
and clause[2].replace('%%', '__').endswith('%')):
ids = map(int, cls.search(domain, order=[]))
ids = list(map(int, cls.search(domain, order=[])))
domain = [(parent, 'child_of', ids)]
return domain
+1 -1
View File
@@ -35,7 +35,7 @@ class Workflow(object):
result = func(cls, filtered, *args, **kwargs)
if to_update:
for record in to_update.keys():
for record in list(to_update.keys()):
current_state = getattr(record, cls._transition_state)
if current_state != to_update[record]:
del to_update[record]
+6 -6
View File
@@ -5,7 +5,7 @@ import sys
import itertools
import logging
import imp
import ConfigParser
import configparser
from glob import iglob
from collections import defaultdict
@@ -47,9 +47,9 @@ update_egg_modules()
def get_module_info(name):
"Return the content of the tryton.cfg"
module_config = ConfigParser.ConfigParser()
module_config = configparser.ConfigParser()
with tools.file_open(os.path.join(name, 'tryton.cfg')) as fp:
module_config.readfp(fp)
module_config.read_file(fp)
directory = os.path.dirname(fp.name)
info = dict(module_config.items('tryton'))
info['directory'] = directory
@@ -74,7 +74,7 @@ class Graph(dict):
return node
def __iter__(self):
for node in sorted(self.itervalues(), key=lambda n: (n.depth, n.name)):
for node in sorted(self.values(), key=lambda n: (n.depth, n.name)):
yield node
@@ -174,7 +174,7 @@ def load_module_graph(graph, pool, update=None, lang=None):
package_state = 'to activate'
for child in node:
module2state[child.name] = package_state
for type in classes.keys():
for type in list(classes.keys()):
for cls in classes[type]:
logger.info('%s:register %s', module, cls.__name__)
cls.__register__(module)
@@ -206,7 +206,7 @@ def load_module_graph(graph, pool, update=None, lang=None):
continue
lang2filenames[lang2].append(filename)
base_path_position = len(node.info['directory']) + 1
for language, files in lang2filenames.iteritems():
for language, files in lang2filenames.items():
filenames = [f[base_path_position:] for f in files]
logger.info('%s:loading %s', module, ','.join(filenames))
Translation = pool.get('ir.translation')
+7 -9
View File
@@ -5,7 +5,7 @@ from threading import RLock
import logging
from trytond.modules import load_modules, register_classes
from trytond.transaction import Transaction
import __builtin__
import builtins
__all__ = ['Pool', 'PoolMeta', 'PoolBase', 'isregisteredby']
@@ -24,9 +24,7 @@ class PoolMeta(type):
return new
class PoolBase(object):
__metaclass__ = PoolMeta
class PoolBase(object, metaclass=PoolMeta):
@classmethod
def __setup__(cls):
pass
@@ -99,7 +97,7 @@ class Pool(object):
Start/restart the Pool
'''
with cls._lock:
for classes in Pool.classes.itervalues():
for classes in Pool.classes.values():
classes.clear()
register_classes()
cls._started = True
@@ -181,7 +179,7 @@ class Pool(object):
if type == 'report':
from trytond.report import Report
# Keyword argument 'type' conflicts with builtin function
cls = __builtin__.type(str(name), (Report,), {})
cls = builtins.type(str(name), (Report,), {})
cls.__setup__()
self.add(cls, type)
return cls
@@ -201,7 +199,7 @@ class Pool(object):
:param type: the type
:return: an iterator
'''
return self._pool[self.database_name][type].iteritems()
return self._pool[self.database_name][type].items()
def fill(self, module, modules):
'''
@@ -230,8 +228,8 @@ class Pool(object):
if classes is None:
classes = {}
for type_ in self._pool[self.database_name]:
classes[type_] = self._pool[self.database_name][type_].values()
for type_, lst in classes.iteritems():
classes[type_] = list(self._pool[self.database_name][type_].values())
for type_, lst in classes.items():
for cls in lst:
cls.__setup__()
for cls in lst:
+2 -2
View File
@@ -41,7 +41,7 @@ JSONDecoder.register('timedelta',
def _bytes_decoder(dct):
cast = bytearray if bytes == str else bytes
return cast(base64.decodestring(dct['base64'].encode('utf-8')))
return cast(base64.decodebytes(dct['base64'].encode('utf-8')))
JSONDecoder.register('bytes', _bytes_decoder)
JSONDecoder.register('Decimal', lambda dct: Decimal(dct['decimal']))
@@ -93,7 +93,7 @@ JSONEncoder.register(datetime.timedelta,
})
_bytes_encoder = lambda o: {
'__class__': 'bytes',
'base64': base64.encodestring(o).decode('utf-8'),
'base64': base64.encodebytes(o).decode('utf-8'),
}
JSONEncoder.register(bytes, _bytes_encoder)
JSONEncoder.register(bytearray, _bytes_encoder)
+1 -1
View File
@@ -184,7 +184,7 @@ def user_application(name, json=True):
transaction.set_context(_check_access=True):
try:
response = func(request, *args, **kwargs)
except Exception, e:
except Exception as e:
if isinstance(e, HTTPException):
raise
logger.error('%s', request, exc_info=True)
+4 -4
View File
@@ -1,6 +1,6 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import xmlrpclib as client
import xmlrpc.client as client
import datetime
import logging
@@ -69,9 +69,9 @@ if bytes == str:
def dump_struct(self, value, write, escape=client.escape):
converted_value = {}
for k, v in value.items():
if type(k) in (int, long):
k = str(int(k))
elif type(k) == float:
if isinstance(k, int):
k = str(k)
elif isinstance(k, float):
k = repr(k)
converted_value[k] = v
return self.dump_struct(converted_value, write, escape=escape)
+46 -64
View File
@@ -4,23 +4,7 @@ import json
import datetime
from decimal import Decimal
from dateutil.relativedelta import relativedelta
from functools import reduce, wraps
def reduced_type(types):
types = types.copy()
for k, r in [(long, int), (str, basestring), (unicode, basestring)]:
if k in types:
types.remove(k)
types.add(r)
return types
def reduce_type(func):
@wraps(func)
def wrapper(*args, **kwargs):
return reduced_type(func(*args, **kwargs))
return wrapper
from functools import reduce
class PYSON(object):
@@ -36,20 +20,20 @@ class PYSON(object):
raise NotImplementedError
def __invert__(self):
if self.types() != set([bool]):
if self.types() != {bool}:
return Not(Bool(self))
else:
return Not(self)
def __and__(self, other):
if (isinstance(other, PYSON)
and other.types() != set([bool])):
and other.types() != {bool}):
other = Bool(other)
if (isinstance(self, And)
and not isinstance(self, Or)):
self._statements.append(other)
return self
if self.types() != set([bool]):
if self.types() != {bool}:
return And(Bool(self), other)
else:
return And(self, other)
@@ -58,12 +42,12 @@ class PYSON(object):
def __or__(self, other):
if (isinstance(other, PYSON)
and other.types() != set([bool])):
and other.types() != {bool}):
other = Bool(other)
if isinstance(self, Or):
self._statements.append(other)
return self
if self.types() != set([bool]):
if self.types() != {bool}:
return Or(Bool(self), other)
else:
return Or(self, other)
@@ -161,12 +145,11 @@ class Eval(PYSON):
'd': self._default,
}
@reduce_type
def types(self):
if isinstance(self._default, PYSON):
return self._default.types()
else:
return set([type(self._default)])
return {type(self._default)}
@staticmethod
def eval(dct, context):
@@ -178,7 +161,7 @@ class Not(PYSON):
def __init__(self, v):
super(Not, self).__init__()
if isinstance(v, PYSON):
assert v.types() == set([bool]), 'value must be boolean'
assert v.types() == {bool}, 'value must be boolean'
else:
assert isinstance(v, bool), 'value must be boolean'
self._value = v
@@ -194,7 +177,7 @@ class Not(PYSON):
}
def types(self):
return set([bool])
return {bool}
@staticmethod
def eval(dct, context):
@@ -218,7 +201,7 @@ class Bool(PYSON):
}
def types(self):
return set([bool])
return {bool}
@staticmethod
def eval(dct, context):
@@ -232,7 +215,7 @@ class And(PYSON):
statements = list(statements) + kwargs.get('s', [])
for statement in statements:
if isinstance(statement, PYSON):
assert statement.types() == set([bool]), \
assert statement.types() == {bool}, \
'statement must be boolean'
else:
assert isinstance(statement, bool), \
@@ -251,7 +234,7 @@ class And(PYSON):
}
def types(self):
return set([bool])
return {bool}
@staticmethod
def eval(dct, context):
@@ -278,11 +261,11 @@ class Equal(PYSON):
if isinstance(statement1, PYSON):
types1 = statement1.types()
else:
types1 = reduced_type(set([type(s1)]))
types1 = {type(s1)}
if isinstance(statement2, PYSON):
types2 = statement2.types()
else:
types2 = reduced_type(set([type(s2)]))
types2 = {type(s2)}
assert types1 == types2, 'statements must have the same type'
self._statement1 = statement1
self._statement2 = statement2
@@ -299,7 +282,7 @@ class Equal(PYSON):
}
def types(self):
return set([bool])
return {bool}
@staticmethod
def eval(dct, context):
@@ -313,13 +296,13 @@ class Greater(PYSON):
super(Greater, self).__init__()
for i in (statement1, statement2):
if isinstance(i, PYSON):
assert i.types().issubset({int, long, float, type(None)}), \
assert i.types().issubset({int, float, type(None)}), \
'statement must be an integer or a float'
else:
assert isinstance(i, (int, long, float, type(None))), \
assert isinstance(i, (int, float, type(None))), \
'statement must be an integer or a float'
if isinstance(equal, PYSON):
assert equal.types() == set([bool])
assert equal.types() == {bool}
else:
assert isinstance(equal, bool)
self._statement1 = statement1
@@ -339,14 +322,14 @@ class Greater(PYSON):
}
def types(self):
return set([bool])
return {bool}
@staticmethod
def _convert(dct):
for i in ('s1', 's2'):
if dct[i] is None:
dct[i] = 0.0
if not isinstance(dct[i], (int, long, float)):
if not isinstance(dct[i], (int, float)):
dct = dct.copy()
dct[i] = float(dct[i])
return dct
@@ -382,18 +365,18 @@ class If(PYSON):
condition, then_statement, else_statement = c, t, e
super(If, self).__init__()
if isinstance(condition, PYSON):
assert condition.types() == set([bool]), \
assert condition.types() == {bool}, \
'condition must be boolean'
else:
assert isinstance(condition, bool), 'condition must be boolean'
if isinstance(then_statement, PYSON):
then_types = then_statement.types()
else:
then_types = reduced_type(set([type(then_statement)]))
then_types = {type(then_statement)}
if isinstance(else_statement, PYSON):
else_types = else_statement.types()
else:
else_types = reduced_type(set([type(else_statement)]))
else_types = {type(else_statement)}
assert then_types == else_types, \
'then and else statements must be the same type'
self._condition = condition
@@ -412,12 +395,11 @@ class If(PYSON):
'e': self._else_statement,
}
@reduce_type
def types(self):
if isinstance(self._then_statement, PYSON):
return self._then_statement.types()
else:
return set([type(self._then_statement)])
return {type(self._then_statement)}
@staticmethod
def eval(dct, context):
@@ -433,14 +415,14 @@ class Get(PYSON):
obj, key, default = v, k, d
super(Get, self).__init__()
if isinstance(obj, PYSON):
assert obj.types() == set([dict]), 'obj must be a dict'
assert obj.types() == {dict}, 'obj must be a dict'
else:
assert isinstance(obj, dict), 'obj must be a dict'
self._obj = obj
if isinstance(key, PYSON):
assert key.types() == set([basestring]), 'key must be a string'
assert key.types() == {str}, 'key must be a string'
else:
assert isinstance(key, basestring), 'key must be a string'
assert isinstance(key, str), 'key must be a string'
self._key = key
self._default = default
@@ -456,12 +438,11 @@ class Get(PYSON):
'd': self._default,
}
@reduce_type
def types(self):
if isinstance(self._default, PYSON):
return self._default.types()
else:
return set([type(self._default)])
return {type(self._default)}
@staticmethod
def eval(dct, context):
@@ -474,20 +455,20 @@ class In(PYSON):
key, obj = k, v
super(In, self).__init__()
if isinstance(key, PYSON):
assert key.types().issubset(set([basestring, int])), \
assert key.types().issubset({str, int}), \
'key must be a string or an integer or a long'
else:
assert isinstance(key, (basestring, int, long)), \
assert isinstance(key, (str, int)), \
'key must be a string or an integer or a long'
if isinstance(obj, PYSON):
assert obj.types().issubset(set([dict, list])), \
assert obj.types().issubset({dict, list}), \
'obj must be a dict or a list'
if obj.types() == set([dict]):
assert isinstance(key, basestring), 'key must be a string'
if obj.types() == {dict}:
assert isinstance(key, str), 'key must be a string'
else:
assert isinstance(obj, (dict, list))
if isinstance(obj, dict):
assert isinstance(key, basestring), 'key must be a string'
assert isinstance(key, str), 'key must be a string'
self._key = key
self._obj = obj
@@ -503,7 +484,7 @@ class In(PYSON):
}
def types(self):
return set([bool])
return {bool}
@staticmethod
def eval(dct, context):
@@ -523,10 +504,10 @@ class Date(PYSON):
super(Date, self).__init__()
for i in (year, month, day, delta_years, delta_months, delta_days):
if isinstance(i, PYSON):
assert i.types().issubset(set([int, long, type(None)])), \
assert i.types().issubset({int, type(None)}), \
'%s must be an integer or None' % (i,)
else:
assert isinstance(i, (int, long, type(None))), \
assert isinstance(i, (int, type(None))), \
'%s must be an integer or None' % (i,)
self._year = year
self._month = month
@@ -552,7 +533,7 @@ class Date(PYSON):
}
def types(self):
return set([datetime.date])
return {datetime.date}
@staticmethod
def eval(dct, context):
@@ -587,10 +568,10 @@ class DateTime(Date):
for i in (hour, minute, second, microsecond,
delta_hours, delta_minutes, delta_seconds, delta_microseconds):
if isinstance(i, PYSON):
assert i.types() == set([int, type(None)]), \
assert i.types() == {int, type(None)}, \
'%s must be an integer or None' % (i,)
else:
assert isinstance(i, (int, long, type(None))), \
assert isinstance(i, (int, type(None))), \
'%s must be an integer or None' % (i,)
self._hour = hour
self._minute = minute
@@ -624,7 +605,7 @@ class DateTime(Date):
return res
def types(self):
return set([datetime.datetime])
return {datetime.datetime}
@staticmethod
def eval(dct, context):
@@ -651,10 +632,10 @@ class Len(PYSON):
def __init__(self, v):
super(Len, self).__init__()
if isinstance(v, PYSON):
assert v.types().issubset(set([dict, list, basestring])), \
assert v.types().issubset({dict, list, str}), \
'value must be a dict or a list or a string'
else:
assert isinstance(v, (dict, list, basestring)), \
assert isinstance(v, (dict, list, str)), \
'value must be a dict or list or a string'
self._value = v
@@ -669,7 +650,7 @@ class Len(PYSON):
}
def types(self):
return set([int])
return {int}
@staticmethod
def eval(dct, context):
@@ -694,7 +675,8 @@ class Id(PYSON):
return ModelData.get_id(self._module, self._fs_id)
def types(self):
return set([int])
return {int}
CONTEXT = {
'Eval': Eval,
+2 -2
View File
@@ -180,7 +180,7 @@ class Report(URLMixin, PoolBase):
oext = 'zip'
else:
oext, content = cls._execute(records, data, action_report)
if not isinstance(content, unicode):
if not isinstance(content, str):
content = bytearray(content) if bytes == str else bytes(content)
return (oext, content, action_report.direct_print, action_report.name)
@@ -230,7 +230,7 @@ class Report(URLMixin, PoolBase):
return '%s,%s' % (Model.__name__, self.id)
def __unicode__(self):
return u'%s,%s' % (Model.__name__, self.id)
return '%s,%s' % (Model.__name__, self.id)
return [TranslateModel(id) for id in ids]
@classmethod
+3 -3
View File
@@ -18,11 +18,11 @@ class MenuMany2Many(fields.Many2Many):
menu_ids = list(set(chain(*res.values())))
test_ids = []
for sub_ids in grouped_slice(menu_ids):
test_ids.append(map(int, Menu.search([
test_ids.append(list(map(int, Menu.search([
('id', 'in', sub_ids),
])))
]))))
menu_ids = set(chain(*test_ids))
for group_id, ids in res.iteritems():
for group_id, ids in res.items():
res[group_id] = tuple(id_ for id_ in ids if id_ in menu_ids)
return res
+7 -13
View File
@@ -166,14 +166,12 @@ class ModelButtonGroup(DeactivableMixin, ModelSQL):
pool.get('ir.model.button')._groups_cache.clear()
class ModelButtonRule:
__metaclass__ = PoolMeta
class ModelButtonRule(metaclass=PoolMeta):
__name__ = 'ir.model.button.rule'
group = fields.Many2One('res.group', "Group", ondelete='CASCADE')
class ModelButtonClick:
__metaclass__ = PoolMeta
class ModelButtonClick(metaclass=PoolMeta):
__name__ = 'ir.model.button.click'
user = fields.Many2One('res.user', "User", ondelete='CASCADE')
@@ -202,8 +200,7 @@ class RuleGroupGroup(ModelSQL):
super(RuleGroupGroup, cls).__register__(module_name)
class Lang:
__metaclass__ = PoolMeta
class Lang(metaclass=PoolMeta):
__name__ = 'ir.lang'
@classmethod
@@ -213,8 +210,7 @@ class Lang:
Pool().get('res.user')._get_preferences_cache.clear()
class SequenceType:
__metaclass__ = PoolMeta
class SequenceType(metaclass=PoolMeta):
__name__ = 'ir.sequence.type'
groups = fields.Many2Many('ir.sequence.type-res.group', 'sequence_type',
'group', 'User Groups',
@@ -252,8 +248,7 @@ class SequenceTypeGroup(ModelSQL):
Rule._domain_get_cache.clear()
class Sequence:
__metaclass__ = PoolMeta
class Sequence(metaclass=PoolMeta):
__name__ = 'ir.sequence'
groups = fields.Function(fields.Many2Many('res.group', None, None,
'User Groups'), 'get_groups', searcher='search_groups')
@@ -266,7 +261,7 @@ class Sequence:
code2seq.setdefault(sequence.code, []).append(sequence.id)
sequence_types = SequenceType.search([
('code', 'in', code2seq.keys()),
('code', 'in', list(code2seq.keys())),
])
groups = {}
@@ -291,8 +286,7 @@ class SequenceStrict(Sequence):
__name__ = 'ir.sequence.strict'
class ModuleConfigWizardItem:
__metaclass__ = PoolMeta
class ModuleConfigWizardItem(metaclass=PoolMeta):
__name__ = 'ir.module.config_wizard.item'
@classmethod
+14 -14
View File
@@ -1,7 +1,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
"User"
from __future__ import division
import copy
import string
import random
@@ -18,7 +18,7 @@ except ImportError:
import ipaddress
from email.header import Header
from functools import wraps
from itertools import groupby, ifilter
from itertools import groupby
from operator import attrgetter
from ast import literal_eval
@@ -277,7 +277,7 @@ class User(DeactivableMixin, ModelSQL, ModelView):
@classmethod
def validate_password(cls, password, users):
password_b = password
if isinstance(password, unicode):
if isinstance(password, str):
password_b = password.encode('utf-8')
length = config.getint('password', 'length', default=0)
if length > 0:
@@ -349,7 +349,7 @@ class User(DeactivableMixin, ModelSQL, ModelView):
timestamp = session.write_date or session.create_date
return abs(timestamp - now) < timeout
result.update(dict((i, len(list(g)))
for i, g in groupby(ifilter(filter_, sessions),
for i, g in groupby(filter(filter_, sessions),
attrgetter('create_uid.id'))))
return result
@@ -388,7 +388,7 @@ class User(DeactivableMixin, ModelSQL, ModelView):
args.extend((users, cls._convert_vals(values)))
super(User, cls).write(*args)
# Clean cursor cache as it could be filled by domain_get
for cache in Transaction().cache.itervalues():
for cache in Transaction().cache.values():
if cls.__name__ in cache:
for user in all_users:
if user.id in cache[cls.__name__]:
@@ -685,35 +685,35 @@ class User(DeactivableMixin, ModelSQL, ModelView):
def hash_sha1(cls, password):
salt = gen_password()
salted_password = password + salt
if isinstance(salted_password, unicode):
if isinstance(salted_password, str):
salted_password = salted_password.encode('utf-8')
hash_ = hashlib.sha1(salted_password).hexdigest()
return '$'.join(['sha1', hash_, salt])
@classmethod
def check_sha1(cls, password, hash_):
if isinstance(password, unicode):
if isinstance(password, str):
password = password.encode('utf-8')
hash_method, hash_, salt = hash_.split('$', 2)
salt = salt or ''
if isinstance(salt, unicode):
if isinstance(salt, str):
salt = salt.encode('utf-8')
assert hash_method == 'sha1'
return hash_ == hashlib.sha1(password + salt).hexdigest()
@classmethod
def hash_bcrypt(cls, password):
if isinstance(password, unicode):
if isinstance(password, str):
password = password.encode('utf-8')
hash_ = bcrypt.hashpw(password, bcrypt.gensalt()).decode('utf-8')
return '$'.join(['bcrypt', hash_])
@classmethod
def check_bcrypt(cls, password, hash_):
if isinstance(password, unicode):
if isinstance(password, str):
password = password.encode('utf-8')
hash_method, hash_ = hash_.split('$', 1)
if isinstance(hash_, unicode):
if isinstance(hash_, str):
hash_ = hash_.encode('utf-8')
assert hash_method == 'bcrypt'
return hash_ == bcrypt.hashpw(password, hash_)
@@ -751,11 +751,11 @@ class LoginAttempt(ModelSQL):
ip_network = ''
if context.get('_request') and context['_request'].get('remote_addr'):
ip_address = ipaddress.ip_address(
unicode(context['_request']['remote_addr']))
str(context['_request']['remote_addr']))
prefix = config.getint(
'session', 'ip_network_%s' % ip_address.version)
ip_network = ipaddress.ip_network(
unicode(context['_request']['remote_addr']))
str(context['_request']['remote_addr']))
ip_network = ip_network.supernet(new_prefix=prefix)
return ip_address, ip_network
@@ -922,7 +922,7 @@ class UserApplication(Workflow, ModelSQL, ModelView):
@classmethod
def default_key(cls):
return ''.join(uuid.uuid4().hex for _ in xrange(4))
return ''.join(uuid.uuid4().hex for _ in range(4))
@classmethod
def default_state(cls):
+2 -2
View File
@@ -38,7 +38,7 @@ class RPC(object):
context = args.pop()
context = copy.deepcopy(context)
timestamp = None
for key in context.keys():
for key in list(context.keys()):
if key == '_timestamp':
timestamp = context[key]
# Remove all private keyword but _datetime for history
@@ -48,7 +48,7 @@ class RPC(object):
def instance(data):
with Transaction().set_context(context):
if isinstance(data, (int, long)):
if isinstance(data, int):
return obj(data)
elif isinstance(data, dict):
return obj(**data)
+5 -6
View File
@@ -2,9 +2,8 @@
# this repository contains the full copyright notices and license terms.
import logging
import smtplib
import urllib
from email.message import Message
from urlparse import parse_qs
from urllib.parse import parse_qs, unquote_plus
from .config import config, parse_uri
from .transaction import Transaction
@@ -36,7 +35,7 @@ def sendmail(from_addr, to_addrs, msg, server=None):
logger.error('fail to send email', exc_info=True)
else:
if senderrs:
logger.warn('fail to send email to %s', senderrs)
logger.warning('fail to send email to %s', senderrs)
if quit:
server.quit()
@@ -48,7 +47,7 @@ def get_smtp_server(uri=None):
extra = {}
if uri.query:
cast = {'timeout': int}
for key, value in parse_qs(uri.query, strict_parsing=True).iteritems():
for key, value in parse_qs(uri.query, strict_parsing=True).items():
extra[key] = cast.get(key, lambda a: a)(value[0])
if uri.scheme.startswith('smtps'):
server = smtplib.SMTP_SSL(uri.hostname, uri.port, **extra)
@@ -60,8 +59,8 @@ def get_smtp_server(uri=None):
if uri.username and uri.password:
server.login(
urllib.unquote_plus(uri.username),
urllib.unquote_plus(uri.password))
unquote_plus(uri.username),
unquote_plus(uri.password))
return server
+1 -1
View File
@@ -17,7 +17,7 @@ from .access import *
from .wizard import *
from .workflow import *
from .copy_ import *
from history import *
from .history import *
from .field_context import *
from . import model
from . import modelstorage
+1 -2
View File
@@ -43,9 +43,8 @@ class ExportData(ModelSQL):
])
class ExportDataTarget2:
class ExportDataTarget2(metaclass=PoolMeta):
'Export Date Target'
__metaclass__ = PoolMeta
__name__ = 'test.export_data.target'
one2many = fields.Many2One('test.export_data', 'Export Data')
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import logging
+1 -1
View File
@@ -168,7 +168,7 @@ class ExportDataTestCase(unittest.TestCase):
export1, = ExportData.create([{
'date': datetime.date(2010, 1, 1),
}])
self.assert_(ExportData.export_data([export1],
self.assertTrue(ExportData.export_data([export1],
['date']) == [[datetime.date(2010, 1, 1)]])
export2, = ExportData.create([{
+12 -12
View File
@@ -32,10 +32,10 @@ class CommonTestCaseMixin:
Char = self.Char()
char, = Char.create([{
'char': u"é",
'char': "é",
}])
self.assertEqual(char.char, u"é")
self.assertEqual(char.char, "é")
@with_transaction()
def test_search_equals(self):
@@ -74,11 +74,11 @@ class CommonTestCaseMixin:
"Test search char equals unicode"
Char = self.Char()
char, = Char.create([{
'char': u"é",
'char': "é",
}])
chars = Char.search([
('char', '=', u"é"),
('char', '=', "é"),
])
self.assertListEqual(chars, [char])
@@ -88,7 +88,7 @@ class CommonTestCaseMixin:
"Test search char equals non unicode"
Char = self.Char()
char, = Char.create([{
'char': u"é",
'char': "é",
}])
chars = Char.search([
@@ -314,10 +314,10 @@ class CommonTestCaseMixin:
}])
Char.write([char], {
'char': u"é",
'char': "é",
})
self.assertEqual(char.char, u"é")
self.assertEqual(char.char, "é")
class FieldCharTestCase(unittest.TestCase, CommonTestCaseMixin):
@@ -498,7 +498,7 @@ class FieldCharUnaccentedTestCase(unittest.TestCase):
"Test searches without the unaccented feature"
Char = Pool().get('test.char_unaccented_off')
char, = Char.create([{
'char': u'Stéphanie',
'char': 'Stéphanie',
}])
chars_stephanie = Char.search([
@@ -512,7 +512,7 @@ class FieldCharUnaccentedTestCase(unittest.TestCase):
"Test searches of accented value"
Char = Pool().get('test.char_unaccented_on')
char, = Char.create([{
'char': u'Stéphanie',
'char': 'Stéphanie',
}])
chars_stephanie = Char.search([
@@ -526,7 +526,7 @@ class FieldCharUnaccentedTestCase(unittest.TestCase):
"Test searches of unaccented value"
Char = Pool().get('test.char_unaccented_on')
char, = Char.create([{
'char': u'Stephanie',
'char': 'Stephanie',
}])
chars_stephanie = Char.search([
@@ -548,12 +548,12 @@ class FieldCharUnaccentedTestCase(unittest.TestCase):
lang.translatable = True
lang.save()
char, = Char.create([{
'char': u'School',
'char': 'School',
}])
with Transaction().set_context(lang=lang.code):
trans_char = Char(char.id)
trans_char.char = u'École'
trans_char.char = 'École'
trans_char.save()
chars_ecole = Char.search([
+7 -7
View File
@@ -30,10 +30,10 @@ class CommonTestCaseMixin:
Text = self.Text()
text, = Text.create([{
'text': u"é",
'text': "é",
}])
self.assertEqual(text.text, u"é")
self.assertEqual(text.text, "é")
@with_transaction()
def test_create_multiline(self):
@@ -83,11 +83,11 @@ class CommonTestCaseMixin:
"Test search text equals unicode"
Text = self.Text()
text, = Text.create([{
'text': u"é",
'text': "é",
}])
texts = Text.search([
('text', '=', u"é"),
('text', '=', "é"),
])
self.assertListEqual(texts, [text])
@@ -97,7 +97,7 @@ class CommonTestCaseMixin:
"Test search text equals non unicode"
Text = self.Text()
text, = Text.create([{
'text': u"é",
'text': "é",
}])
texts = Text.search([
@@ -323,10 +323,10 @@ class CommonTestCaseMixin:
}])
Text.write([text], {
'text': u"é",
'text': "é",
})
self.assertEqual(text.text, u"é")
self.assertEqual(text.text, "é")
class FieldTextTestCase(unittest.TestCase, CommonTestCaseMixin):
+3 -3
View File
@@ -4,7 +4,7 @@ import os
import shutil
import tempfile
import unittest
from mock import patch
from unittest.mock import patch
from trytond.config import config
from trytond.filestore import filestore
@@ -27,14 +27,14 @@ class FileStoreTestCase(unittest.TestCase):
"Test set"
result = filestore.set(self.data(), prefix='test')
self.assertTrue(result)
self.assertIsInstance(result, basestring)
self.assertIsInstance(result, str)
def test_setmany(self):
"Test setmany"
result = filestore.setmany([self.data(), self.data()], prefix='test')
self.assertIsInstance(result, list)
self.assertEqual(len(result), 2)
self.assertIsInstance(result[0], basestring)
self.assertIsInstance(result[0], str)
def test_get(self):
"Test get"
+4 -4
View File
@@ -142,9 +142,9 @@ class HistoryTestCase(unittest.TestCase):
revisions = History.history_revisions([history_id])
self.assertEqual(revisions, [
(third, history_id, u'Administrator'),
(second, history_id, u'Administrator'),
(first, history_id, u'Administrator'),
(third, history_id, 'Administrator'),
(second, history_id, 'Administrator'),
(first, history_id, 'Administrator'),
])
@with_transaction()
@@ -465,7 +465,7 @@ class HistoryTestCase(unittest.TestCase):
transaction = Transaction()
database = transaction.database
for i in xrange(0, 2):
for i in range(0, 2):
history = History(value=-1)
history.save()
+3 -3
View File
@@ -54,9 +54,9 @@ class IrTestCase(ModuleTestCase):
pool = Pool()
Lang = pool.get('ir.lang')
test_data = [
((2016, 8, 3), 'en', '%d %B %Y', u"03 August 2016"),
((2016, 8, 3), 'fr', '%d %B %Y', u"03 ao\xfbt 2016"),
((2016, 8, 3), 'fr', u'%d %B %Y', u"03 ao\xfbt 2016"),
((2016, 8, 3), 'en', '%d %B %Y', "03 August 2016"),
((2016, 8, 3), 'fr', '%d %B %Y', "03 ao\xfbt 2016"),
((2016, 8, 3), 'fr', '%d %B %Y', "03 ao\xfbt 2016"),
]
for date, code, format_, result in test_data:
lang = Lang.get(code)
+4 -4
View File
@@ -3,7 +3,7 @@
# this repository contains the full copyright notices and license terms.
import unittest
import urllib
import urllib.parse
from trytond.tests.test_tryton import activate_module, with_transaction
from trytond.transaction import Transaction
@@ -30,11 +30,11 @@ class UrlTestCase(unittest.TestCase):
self.assertEqual(UrlObject.__url__,
'tryton://%s/%s/model/test.urlobject' % (
HOSTNAME, urllib.quote(db_name)))
HOSTNAME, urllib.parse.quote(db_name)))
self.assertEqual(UrlObject(1).__url__,
'tryton://%s/%s/model/test.urlobject/1' % (
HOSTNAME, urllib.quote(db_name)))
HOSTNAME, urllib.parse.quote(db_name)))
@with_transaction()
def testWizardURL(self):
@@ -45,7 +45,7 @@ class UrlTestCase(unittest.TestCase):
self.assertEqual(UrlWizard.__url__,
'tryton://%s/%s/wizard/test.test_wizard' % (
HOSTNAME, urllib.quote(db_name)))
HOSTNAME, urllib.parse.quote(db_name)))
class MixinTestCase(unittest.TestCase):
+8 -8
View File
@@ -22,12 +22,12 @@ class ModelSingletonTestCase(unittest.TestCase):
Singleton = pool.get('test.singleton')
singleton, = Singleton.read([1], ['name'])
self.assert_(singleton['name'] == 'test')
self.assert_(singleton['id'] == 1)
self.assertTrue(singleton['name'] == 'test')
self.assertTrue(singleton['id'] == 1)
singleton, = Singleton.read([1], ['name'])
self.assert_(singleton['name'] == 'test')
self.assert_(singleton['id'] == 1)
self.assertTrue(singleton['name'] == 'test')
self.assertTrue(singleton['id'] == 1)
singleton, = Singleton.read([1], [
'create_uid',
@@ -38,7 +38,7 @@ class ModelSingletonTestCase(unittest.TestCase):
])
self.assertEqual(singleton['create_uid'], Transaction().user)
self.assertEqual(singleton['create_uid.rec_name'], 'Administrator')
self.assert_(isinstance(singleton['create_date'], datetime))
self.assertTrue(isinstance(singleton['create_date'], datetime))
self.assertEqual(singleton['write_uid'], None)
self.assertEqual(singleton['write_date'], None)
@@ -49,7 +49,7 @@ class ModelSingletonTestCase(unittest.TestCase):
Singleton = pool.get('test.singleton')
singleton, = Singleton.create([{'name': 'bar'}])
self.assert_(singleton)
self.assertTrue(singleton)
self.assertEqual(singleton.name, 'bar')
singleton2, = Singleton.create([{'name': 'foo'}])
@@ -115,10 +115,10 @@ class ModelSingletonTestCase(unittest.TestCase):
Singleton = pool.get('test.singleton')
singletons = Singleton.search([])
self.assertEqual(map(int, singletons), [1])
self.assertEqual(list(map(int, singletons)), [1])
singletons = Singleton.search([])
self.assertEqual(map(int, singletons), [1])
self.assertEqual(list(map(int, singletons)), [1])
count = Singleton.search([], count=True)
self.assertEqual(count, 1)
+3 -4
View File
@@ -4,8 +4,7 @@
import unittest
import time
from mock import patch, call
from unittest.mock import patch, call
from trytond import backend
from trytond.exceptions import UserError, ConcurrencyException
@@ -36,10 +35,10 @@ class ModelSQLTestCase(unittest.TestCase):
'desc': '',
'integer': 0,
}
for key, value in fields.iteritems():
for key, value in fields.items():
try:
Modelsql.create([{key: value}])
except UserError, err:
except UserError as err:
# message must not quote key
msg = "'%s' not missing but quoted in error: '%s'" % (key,
err.message)
+1 -1
View File
@@ -87,7 +87,7 @@ class ModelStorageTestCase(unittest.TestCase):
self.assertDictEqual(record.context, record_context)
record = ModelStorageContext(record.id)
self.assertDictContainsSubset({'foo': 'bar'}, record.context)
self.assertEqual(record.context.get('foo'), 'bar')
@with_transaction()
def test_save_mixed_context(self):
+2 -1
View File
@@ -2,7 +2,8 @@
# this repository contains the full copyright notices and license terms.
import unittest
from mock import patch
from unittest.mock import patch
from lxml import etree
from trytond.tests.test_tryton import activate_module, with_transaction
+4 -3
View File
@@ -3,7 +3,8 @@
# this repository contains the full copyright notices and license terms.
import sys
import unittest
from mock import patch
from unittest.mock import patch
from trytond.tests.test_tryton import activate_module, with_transaction
from trytond.transaction import Transaction
from trytond.pool import Pool
@@ -16,7 +17,7 @@ class MPTTTestCase(unittest.TestCase):
def setUpClass(cls):
activate_module('tests')
def check_tree(self, parent_id=None, left=-1, right=sys.maxint):
def check_tree(self, parent_id=None, left=-1, right=sys.maxsize):
pool = Pool()
Mptt = pool.get('test.mptt')
@@ -43,7 +44,7 @@ class MPTTTestCase(unittest.TestCase):
(child, child.left, next_left)
next_left = child.right
childs.reverse()
previous_right = sys.maxint
previous_right = sys.maxsize
for child in childs:
assert child.right < previous_right, \
'%s: right %d >= previous right %d' \
+1 -1
View File
@@ -20,7 +20,7 @@ class SequenceOrderedMixinTestCase(unittest.TestCase):
Order = pool.get('test.order.sequence')
models = []
for i in reversed(range(1, 4)):
for i in reversed(list(range(1, 4))):
models.append(Order(sequence=i))
Order.save(models)
models.reverse()
+3 -3
View File
@@ -28,7 +28,7 @@ class PYSONTestCase(unittest.TestCase):
'd': 'foo',
})
self.assertEqual(pyson.Eval('test', 'foo').types(), set([basestring]))
self.assertEqual(pyson.Eval('test', 'foo').types(), set([str]))
self.assertEqual(pyson.Eval('test', 1).types(), set([int]))
eval = pyson.PYSONEncoder().encode(pyson.Eval('test', 0))
@@ -310,7 +310,7 @@ class PYSONTestCase(unittest.TestCase):
self.assertRaises(AssertionError, pyson.If, True, 'foo', False)
self.assertEqual(pyson.If(True, 'foo', 'bar').types(),
set([basestring]))
set([str]))
self.assertEqual(pyson.If(True, False, True).types(), set([bool]))
eval = pyson.PYSONEncoder().encode(pyson.If(True, 'foo', 'bar'))
@@ -335,7 +335,7 @@ class PYSONTestCase(unittest.TestCase):
self.assertRaises(AssertionError, pyson.Get, {}, 1, 'default')
self.assertEqual(pyson.Get({}, 'foo', 'default').types(),
set([basestring]))
set([str]))
self.assertEqual(pyson.Get({}, 'foo', True).types(), set([bool]))
eval = pyson.PYSONEncoder().encode(pyson.Get(
+1 -2
View File
@@ -1,8 +1,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import unittest
from mock import Mock, DEFAULT, call
from unittest.mock import Mock, DEFAULT, call
from trytond.tests.test_tryton import with_transaction, activate_module
from trytond.rpc import RPC
+2 -4
View File
@@ -1,10 +1,9 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import unittest
import smtplib
import sys
import unittest
from email.message import Message
from mock import Mock, patch, call
from unittest.mock import Mock, patch, call
from trytond.sendmail import (
sendmail_transactional, sendmail, SMTPDataManager, get_smtp_server)
@@ -68,7 +67,6 @@ class SendmailTestCase(unittest.TestCase):
SMTP.assert_called_once_with('localhost', 25)
server.starttls.assert_called_once_with()
@unittest.skipIf(sys.version_info < (2, 7, 4), "python bug #9374")
def test_get_smtp_server_extra_parameters(self):
'Test get_smtp_server uri extra parameters'
with patch.object(smtplib, 'SMTP') as SMTP:
+24 -18
View File
@@ -22,26 +22,26 @@ class ToolsTestCase(unittest.TestCase):
def test_reduce_ids_continue(self):
'Test reduce_ids continue list'
self.assertEqual(reduce_ids(self.table.id, range(10)),
self.assertEqual(reduce_ids(self.table.id, list(range(10))),
sql.operators.Or(((self.table.id >= 0) & (self.table.id <= 9),)))
def test_reduce_ids_one_hole(self):
'Test reduce_ids continue list with one hole'
self.assertEqual(reduce_ids(self.table.id, range(10) + range(20, 30)),
self.assertEqual(reduce_ids(self.table.id, list(range(10)) + list(range(20, 30))),
((self.table.id >= 0) & (self.table.id <= 9))
| ((self.table.id >= 20) & (self.table.id <= 29)))
def test_reduce_ids_short_continue(self):
'Test reduce_ids short continue list'
self.assertEqual(reduce_ids(self.table.id, range(4)),
sql.operators.Or((self.table.id.in_(range(4)),)))
self.assertEqual(reduce_ids(self.table.id, list(range(4))),
sql.operators.Or((self.table.id.in_(list(range(4))),)))
def test_reduce_ids_complex(self):
'Test reduce_ids complex list'
self.assertEqual(reduce_ids(self.table.id,
range(10) + range(25, 30) + range(15, 20)),
list(range(10)) + list(range(25, 30)) + list(range(15, 20))),
(((self.table.id >= 0) & (self.table.id <= 14))
| (self.table.id.in_(range(25, 30)))))
| (self.table.id.in_(list(range(25, 30))))))
def test_reduce_ids_complex_small_continue(self):
'Test reduce_ids complex list with small continue'
@@ -61,11 +61,11 @@ class ToolsTestCase(unittest.TestCase):
def test_datetime_strftime(self):
'Test datetime_strftime'
self.assert_(datetime_strftime(datetime.date(2005, 3, 2),
self.assertTrue(datetime_strftime(datetime.date(2005, 3, 2),
'%Y-%m-%d'), '2005-03-02')
self.assert_(datetime_strftime(datetime.date(1805, 3, 2),
self.assertTrue(datetime_strftime(datetime.date(1805, 3, 2),
'%Y-%m-%d'), '1805-03-02')
self.assert_(datetime_strftime(datetime.datetime(2005, 3, 2, 0, 0, 0),
self.assertTrue(datetime_strftime(datetime.datetime(2005, 3, 2, 0, 0, 0),
'%Y-%m-%d'), '2005-03-02')
with self.assertRaises(TypeError):
datetime_strftime(None, '%Y-%m-%d')
@@ -122,21 +122,27 @@ class ToolsTestCase(unittest.TestCase):
def test_file_open(self):
"Test file_open"
self.assertTrue(file_open('__init__.py', subdir=None))
self.assertTrue(file_open('ir/__init__.py'))
with file_open('__init__.py', subdir=None) as fp:
self.assertTrue(fp)
with self.assertRaisesRegexp(IOError, "File not found :"):
file_open('ir/noexist')
with file_open('ir/__init__.py') as fp:
self.assertTrue(fp)
with self.assertRaisesRegexp(IOError, "Permission denied:"):
file_open('/etc/passwd')
with self.assertRaisesRegex(IOError, "File not found :"):
with file_open('ir/noexist'):
pass
with self.assertRaisesRegexp(IOError, "Permission denied:"):
file_open('../../foo')
with self.assertRaisesRegex(IOError, "Permission denied:"):
with file_open('/etc/passwd'):
pass
with self.assertRaisesRegex(IOError, "Permission denied:"):
with file_open('../../foo'):
pass
def test_file_open_suffix(self):
"Test file_open from same root name but with a suffix"
with self.assertRaisesRegexp(IOError, "Permission denied:"):
with self.assertRaisesRegex(IOError, "Permission denied:"):
file_open('../trytond_suffix', subdir=None)
+2 -1
View File
@@ -1,7 +1,8 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import unittest
from mock import Mock
from unittest.mock import Mock
from trytond.tests.test_tryton import DB_NAME, USER, CONTEXT, activate_module
from trytond.transaction import Transaction
+7 -7
View File
@@ -44,7 +44,7 @@ class TriggerTestCase(unittest.TestCase):
'action_model': action_model.id,
'action_function': 'test',
}
self.assert_(Trigger.create([values]))
self.assertTrue(Trigger.create([values]))
transaction.rollback()
@@ -387,7 +387,7 @@ class TriggerTestCase(unittest.TestCase):
'name': 'Test',
}])
Trigger.trigger_time()
self.assert_(TRIGGER_LOGS == [([triggered], trigger)])
self.assertTrue(TRIGGER_LOGS == [([triggered], trigger)])
TRIGGER_LOGS.pop()
# Trigger with condition
@@ -402,7 +402,7 @@ class TriggerTestCase(unittest.TestCase):
'name': 'Bar',
})
Trigger.trigger_time()
self.assert_(TRIGGER_LOGS == [([triggered], trigger)])
self.assertTrue(TRIGGER_LOGS == [([triggered], trigger)])
TRIGGER_LOGS.pop()
# Non matching condition
@@ -410,7 +410,7 @@ class TriggerTestCase(unittest.TestCase):
'name': 'Foo',
})
Trigger.trigger_time()
self.assert_(TRIGGER_LOGS == [])
self.assertTrue(TRIGGER_LOGS == [])
# With limit number
Trigger.write([trigger], {
@@ -419,7 +419,7 @@ class TriggerTestCase(unittest.TestCase):
})
Trigger.trigger_time()
Trigger.trigger_time()
self.assert_(TRIGGER_LOGS == [([triggered], trigger)])
self.assertTrue(TRIGGER_LOGS == [([triggered], trigger)])
TRIGGER_LOGS.pop()
# Delete trigger logs of limit number test
@@ -434,7 +434,7 @@ class TriggerTestCase(unittest.TestCase):
})
Trigger.trigger_time()
Trigger.trigger_time()
self.assert_(TRIGGER_LOGS == [([triggered], trigger)])
self.assertTrue(TRIGGER_LOGS == [([triggered], trigger)])
TRIGGER_LOGS.pop()
Transaction().delete = {}
@@ -449,7 +449,7 @@ class TriggerTestCase(unittest.TestCase):
Trigger.trigger_time()
time.sleep(1.2)
Trigger.trigger_time()
self.assert_(TRIGGER_LOGS == [([triggered], trigger),
self.assertTrue(TRIGGER_LOGS == [([triggered], trigger),
([triggered], trigger)])
TRIGGER_LOGS.pop()
TRIGGER_LOGS.pop()
+24 -27
View File
@@ -1,17 +1,17 @@
# -*- coding: utf-8 -*-
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import os
import sys
import unittest
import doctest
import re
import subprocess
import time
from itertools import chain
import operator
from functools import wraps
import inspect
import operator
import os
import subprocess
import sys
import time
import unittest
from functools import reduce
from functools import wraps
from itertools import chain
try:
import pkg_resources
except ImportError:
@@ -108,8 +108,7 @@ def backup_db_cache(name):
def _db_cache_file(path, name, backend_name):
return os.path.join(path, '%s-%s-py%s.dump'
% (name, backend_name, sys.version_info.major))
return os.path.join(path, '%s-%s.dump' % (name, backend_name))
def _sqlite_copy(file_, restore=False):
@@ -289,7 +288,7 @@ class ModuleTestCase(unittest.TestCase):
for mname, model in Pool().iterobject():
if not isregisteredby(model, self.module):
continue
for fname, field in model._fields.iteritems():
for fname, field in model._fields.items():
fields = set()
fields |= get_eval_fields(field.domain)
if hasattr(field, 'digits'):
@@ -309,7 +308,7 @@ class ModuleTestCase(unittest.TestCase):
'Unknown depends %s in "%s"."%s"' % (
list(depends - set(model._fields)), mname, fname))
if issubclass(model, ModelView):
for bname, button in model._buttons.iteritems():
for bname, button in model._buttons.items():
depends = set(button.get('depends', []))
assert depends <= set(model._fields), (
'Unknown depends %s in button "%s"."%s"' % (
@@ -321,7 +320,7 @@ class ModuleTestCase(unittest.TestCase):
for mname, model in Pool().iterobject():
if not isregisteredby(model, self.module):
continue
for fname, field in model._fields.iteritems():
for fname, field in model._fields.items():
for attribute in ['depends', 'on_change', 'on_change_with',
'selection_change_with', 'autocomplete']:
depends = getattr(field, attribute, [])
@@ -470,7 +469,7 @@ class ModuleTestCase(unittest.TestCase):
'wizard': wizard_name,
})
wizard_instance = wizard(session_id)
for state_name, state in wizard_instance.states.iteritems():
for state_name, state in wizard_instance.states.items():
if isinstance(state, StateView):
# Don't test defaults as they may depend on context
state.get_view(wizard_instance, state_name)
@@ -484,7 +483,7 @@ class ModuleTestCase(unittest.TestCase):
for mname, model in Pool().iterobject():
if not isregisteredby(model, self.module):
continue
for field_name, field in model._fields.iteritems():
for field_name, field in model._fields.items():
selection = getattr(field, 'selection', None)
if selection is None:
continue
@@ -510,7 +509,7 @@ class ModuleTestCase(unittest.TestCase):
for mname, model in Pool().iterobject():
if not isregisteredby(model, self.module):
continue
for field_name, field in model._fields.iteritems():
for field_name, field in model._fields.items():
if not isinstance(field, Function):
continue
for func_name in [field.getter, field.setter, field.searcher]:
@@ -661,18 +660,16 @@ def drop_create(name=DB_NAME, lang='en'):
drop_db(name)
create_db(name, lang)
doctest_setup = lambda test: drop_create()
doctest_teardown = lambda test: drop_db()
def doctest_setup(test):
return drop_create()
class Py23DocChecker(doctest.OutputChecker):
def check_output(self, want, got, optionflags):
if sys.version_info[0] > 2:
want = re.sub("u'(.*?)'", "'\\1'", want)
want = re.sub('u"(.*?)"', '"\\1"', want)
return doctest.OutputChecker.check_output(self, want, got, optionflags)
def doctest_teardown(test):
return drop_db()
doctest_checker = Py23DocChecker()
doctest_checker = doctest.OutputChecker()
class TestSuite(unittest.TestSuite):
@@ -682,7 +679,7 @@ class TestSuite(unittest.TestSuite):
try:
exist = db_exist()
break
except DatabaseOperationalError, err:
except DatabaseOperationalError as err:
# Retry on connection error
sys.stderr.write(str(err))
time.sleep(1)
+3 -3
View File
@@ -116,8 +116,8 @@ class UserTestCase(unittest.TestCase):
User = pool.get('res.user')
with self.assertRaises(UserError):
User.validate_password(u'123', [])
User.validate_password(u'1234', [])
User.validate_password('123', [])
User.validate_password('1234', [])
@with_transaction()
def test_validate_password_forbidden(self):
@@ -126,7 +126,7 @@ class UserTestCase(unittest.TestCase):
User = pool.get('res.user')
with self.assertRaises(UserError):
User.validate_password(u'password', [])
User.validate_password('password', [])
@with_transaction()
def test_validate_password_entropy(self):
+2 -2
View File
@@ -21,7 +21,7 @@ class WizardTestCase(unittest.TestCase):
session_id, start_state, end_state = Wizard.create()
self.assertEqual(start_state, 'start')
self.assertEqual(end_state, 'end')
self.assert_(session_id)
self.assertTrue(session_id)
@with_transaction()
def test_delete(self):
@@ -78,7 +78,7 @@ class WizardTestCase(unittest.TestCase):
session_id, start_state, end_state = Wizard.create()
result = Wizard.execute(session_id, {}, start_state)
self.assertEqual(result.keys(), ['view'])
self.assertEqual(list(result.keys()), ['view'])
self.assertEqual(result['view']['defaults'], {
'name': 'Test wizard',
})
+1 -1
View File
@@ -8,7 +8,7 @@ __all__ = ['activate_modules', 'set_user']
def activate_modules(modules):
if isinstance(modules, basestring):
if isinstance(modules, str):
modules = [modules]
cache_name = '-'.join(modules)
if restore_db_cache(cache_name):
+2 -2
View File
@@ -1,6 +1,6 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from itertools import izip
from .misc import *
from .datetime_strftime import *
@@ -19,4 +19,4 @@ def cursor_dict(cursor, size=None):
if not rows:
break
for row in rows:
yield {d[0]: v for d, v in izip(cursor.description, row)}
yield {d[0]: v for d, v in zip(cursor.description, row)}
+32 -62
View File
@@ -1,73 +1,43 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import sys
from tokenize import *
from io import BytesIO, StringIO
from tokenize import tokenize, untokenize, NUMBER, NAME, OP, STRING
from io import BytesIO
# code snippet taken from http://docs.python.org/library/tokenize.html
if sys.version_info < (3,):
def decistmt(s):
"""Substitute Decimals for floats in a string of statements.
def decistmt(s):
"""Substitute Decimals for floats in a string of statements.
>>> from decimal import Decimal
>>> s = 'print +21.3e-5*-.1234/81.7'
>>> decistmt(s)
u"print +Decimal (u'21.3e-5')*-Decimal (u'.1234')/Decimal (u'81.7')"
>>> from decimal import Decimal
>>> s = 'print(+21.3e-5*-.1234/81.7)'
>>> decistmt(s)
"print (+Decimal ('21.3e-5')*-Decimal ('.1234')/Decimal ('81.7'))"
>>> exec(s)
-3.21716034272e-07
>>> exec(decistmt(s))
-3.217160342717258261933904529E-7
The format of the exponent is inherited from the platform C library.
Known cases are "e-007" (Windows) and "e-07" (not Windows). Since
we're only showing 12 digits, and the 13th isn't close to 5, the
rest of the output should be platform-independent.
"""
result = []
g = generate_tokens(StringIO(s.decode('utf-8')).readline) # tokenize the string
for toknum, tokval, _, _, _ in g:
if toknum == NUMBER and '.' in tokval: # replace NUMBER tokens
result.extend([
(NAME, 'Decimal'),
(OP, '('),
(STRING, repr(tokval)),
(OP, ')')
])
else:
result.append((toknum, tokval))
return untokenize(result)
else:
def decistmt(s):
"""Substitute Decimals for floats in a string of statements.
>>> exec(s) #doctest: +ELLIPSIS
-3.217160342717258e-0...7
>>> from decimal import Decimal
>>> s = 'print(+21.3e-5*-.1234/81.7)'
>>> decistmt(s)
"print (+Decimal ('21.3e-5')*-Decimal ('.1234')/Decimal ('81.7'))"
Output from calculations with Decimal should be identical across all
platforms.
The format of the exponent is inherited from the platform C library.
Known cases are "e-007" (Windows) and "e-07" (not Windows). Since
we're only showing 12 digits, and the 13th isn't close to 5, the
rest of the output should be platform-independent.
>>> exec(s) #doctest: +ELLIPSIS
-3.217160342717258e-0...7
Output from calculations with Decimal should be identical across all
platforms.
>>> exec(decistmt(s))
-3.217160342717258261933904529E-7
"""
result = []
g = tokenize(BytesIO(s.encode('utf-8')).readline) # tokenize the string
for toknum, tokval, _, _, _ in g:
if toknum == NUMBER and '.' in tokval: # replace NUMBER tokens
result.extend([
(NAME, 'Decimal'),
(OP, '('),
(STRING, repr(tokval)),
(OP, ')')
])
else:
result.append((toknum, tokval))
return untokenize(result).decode('utf-8')
>>> exec(decistmt(s))
-3.217160342717258261933904529E-7
"""
result = []
g = tokenize(BytesIO(s.encode('utf-8')).readline) # tokenize the string
for toknum, tokval, _, _, _ in g:
if toknum == NUMBER and '.' in tokval: # replace NUMBER tokens
result.extend([
(NAME, 'Decimal'),
(OP, '('),
(STRING, repr(tokval)),
(OP, ')')
])
else:
result.append((toknum, tokval))
return untokenize(result).decode('utf-8')
Loaded 100 of 106 files, more files were not shown because too many files have changed in this diff. Show more