Remove support for Python 2.7
issue7497 review53261002
This commit is contained in:
1 parent
d81519d312
commit
d2a461390a
106 files changed
+1137
-1230
No files matched your search
@@ -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,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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
@@ -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
@@ -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))
|
||||
|
||||
|
||||
@@ -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()
|
||||
@@ -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,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)
|
||||
|
||||
|
||||
@@ -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) +
|
||||
|
||||
@@ -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())
|
||||
|
||||
|
||||
|
||||
@@ -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 ' +
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ''
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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,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
@@ -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')
|
||||
|
||||
@@ -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
File diff suppressed because it is too large.
Load diff
+23
-24
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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()}
|
||||
@@ -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]))))):
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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)
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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([{
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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' \
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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',
|
||||
})
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
@@ -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
Reference in new issue
Block a user