Use direct access to backend classes

issue8836
review258421002
This commit is contained in:
Nicolas Évrard
2019-12-06 17:33:47 +01:00
parent bf98922ff9
commit 8fb13634ea
30 changed files with 107 additions and 154 deletions
+1
View File
@@ -1,3 +1,4 @@
* Use direct access to backend classes
* Add weasyprint support
* Add slugify tool
* Add is_secure, host and http_host to url module
+2 -3
View File
@@ -17,12 +17,11 @@ logger = logging.getLogger(__name__)
def run(options):
Database = backend.get('Database')
main_lang = config.get('database', 'language')
init = {}
for db_name in options.database_names:
init[db_name] = False
database = Database(db_name)
database = backend.Database(db_name)
database.connect()
if options.update:
if not database.test():
@@ -36,7 +35,7 @@ def run(options):
if options.update:
with Transaction().start(db_name, 0) as transaction,\
transaction.connection.cursor() as cursor:
database = Database(db_name)
database = backend.Database(db_name)
database.connect()
if not database.test():
raise Exception('"%s" is not a Tryton database.' % db_name)
+20 -23
View File
@@ -1,7 +1,6 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import importlib
import sys
import urllib.parse
try:
import pkg_resources
@@ -10,29 +9,27 @@ except ImportError:
from trytond.config import config
__all__ = ['name', 'get']
_database_uri = config.get('database', 'uri', default='')
__all__ = ['name', 'Database', 'DatabaseIntegrityError', 'TableHandler']
def name():
return urllib.parse.urlparse(_database_uri).scheme
name = urllib.parse.urlparse(config.get('database', 'uri', default='')).scheme
_modname = 'trytond.backend.%s' % name
try:
_module = importlib.import_module(_modname)
except ImportError:
if not pkg_resources:
raise
for ep in pkg_resources.iter_entry_points('trytond.backend', name):
try:
_module = ep.load()
break
except ImportError:
continue
else:
raise
def get(prop):
db_type = name()
modname = 'trytond.backend.%s' % db_type
try:
module = importlib.import_module(modname)
except ImportError:
if not pkg_resources:
raise
for ep in pkg_resources.iter_entry_points(
'trytond.backend', db_type):
try:
sys.modules[modname] = module = ep.load()
break
except ImportError:
continue
else:
raise
return getattr(module, prop)
Database = _module.Database
DatabaseIntegrityError = _module.DatabaseIntegrityError
DatabaseOperationalError = _module.DatabaseOperationalError
TableHandler = _module.TableHandler
+1 -1
View File
@@ -36,7 +36,6 @@ from sql.operators import BinaryOperator
from trytond.backend.database import DatabaseInterface, SQLType
from trytond.config import config, parse_uri
from trytond.protocols.jsonrpc import JSONDecoder
from trytond.tools.gevent import is_gevent_monkey_patched
__all__ = ['Database', 'DatabaseIntegrityError', 'DatabaseOperationalError']
@@ -561,6 +560,7 @@ register_adapter(Decimal, lambda value: AsIs(str(value)))
def convert_json(value):
from trytond.protocols.jsonrpc import JSONDecoder
return json.loads(value, object_hook=JSONDecoder())
register_default_json(loads=convert_json)
register_default_jsonb(loads=convert_json)
+1 -2
View File
@@ -140,8 +140,7 @@ class LongPollingBus:
@classmethod
def _listen(cls, database):
Database = backend.get('Database')
db = Database(database)
db = backend.Database(database)
if not db.has_channel():
raise NotImplemented
+3 -5
View File
@@ -28,7 +28,7 @@ def _cast(column):
__slots__ = ()
_function = 'DATETIME'
if backend.name() == 'sqlite':
if backend.name == 'sqlite':
column = SQLite_DateTime(column)
return column
@@ -259,8 +259,7 @@ class MemoryCache(BaseCache):
with cls._listener_lock:
listener = cls._listener.pop(dbname, None)
if listener:
Database = backend.get('Database')
database = Database(dbname)
database = backend.Database(dbname)
conn = database.get_connection()
try:
cursor = conn.cursor()
@@ -276,8 +275,7 @@ class MemoryCache(BaseCache):
@classmethod
def _listen(cls, dbname):
Database = backend.get('Database')
database = Database(dbname)
database = backend.Database(dbname)
if not database.has_channel():
raise NotImplementedError
+2 -2
View File
@@ -113,7 +113,6 @@ class Cron(DeactivableMixin, ModelSQL, ModelView):
@classmethod
def run(cls, db_name):
DatabaseOperationalError = backend.get('DatabaseOperationalError')
logger.info('cron started for "%s"', db_name)
now = datetime.datetime.now()
retry = config.getint('database', 'retry')
@@ -136,7 +135,8 @@ class Cron(DeactivableMixin, ModelSQL, ModelView):
transaction.commit()
except Exception as e:
transaction.rollback()
if isinstance(e, DatabaseOperationalError) and count:
if (isinstance(e, backend.DatabaseOperationalError)
and count):
continue
logger.error('Running cron %s', cron.id, exc_info=True)
break
+6 -10
View File
@@ -103,15 +103,14 @@ class Module(ModelSQL, ModelView):
def __register__(cls, module_name):
pool = Pool()
ModelData = pool.get('ir.model.data')
TableHandler = backend.get('TableHandler')
sql_table = cls.__table__()
model_data_sql_table = ModelData.__table__()
cursor = Transaction().connection.cursor()
# Migration from 3.6: remove double module
old_table = 'ir_module_module'
if TableHandler.table_exist(old_table):
TableHandler.table_rename(old_table, cls._table)
if backend.TableHandler.table_exist(old_table):
backend.TableHandler.table_rename(old_table, cls._table)
super(Module, cls).__register__(module_name)
@@ -361,12 +360,10 @@ class ModuleDependency(ModelSQL, ModelView):
@classmethod
def __register__(cls, module_name):
TableHandler = backend.get('TableHandler')
# Migration from 3.6: remove double module
old_table = 'ir_module_module_dependency'
if TableHandler.table_exist(old_table):
TableHandler.table_rename(old_table, cls._table)
if backend.TableHandler.table_exist(old_table):
backend.TableHandler.table_rename(old_table, cls._table)
super(ModuleDependency, cls).__register__(module_name)
@@ -394,7 +391,6 @@ class ModuleConfigWizardItem(sequence_ordered(), ModelSQL, ModelView):
@classmethod
def __register__(cls, module_name):
TableHandler = backend.get('TableHandler')
cursor = Transaction().connection.cursor()
pool = Pool()
ModelData = pool.get('ir.model.data')
@@ -402,8 +398,8 @@ class ModuleConfigWizardItem(sequence_ordered(), ModelSQL, ModelView):
# Migration from 3.6: remove double module
old_table = 'ir_module_module_config_wizard_item'
if TableHandler.table_exist(old_table):
TableHandler.table_rename(old_table, cls._table)
if backend.TableHandler.table_exist(old_table):
backend.TableHandler.table_rename(old_table, cls._table)
cursor.execute(*model_data.update(
columns=[model_data.model],
values=[cls.__name__],
+1 -1
View File
@@ -18,7 +18,7 @@ __all__ = [
'SequenceType', 'Sequence', 'SequenceStrict',
]
sql_sequence = backend.get('Database').has_sequence()
sql_sequence = backend.Database.has_sequence()
class AffixError(ValidationError):
+3 -3
View File
@@ -42,7 +42,7 @@ class Date(Field):
return super().sql_format(value)
def sql_cast(self, expression):
if backend.name() == 'sqlite':
if backend.name == 'sqlite':
return SQLite_Date(expression)
return super(Date, self).sql_cast(expression)
@@ -80,7 +80,7 @@ class Timestamp(FormatMixin, Field):
return super().sql_format(value)
def sql_cast(self, expression):
if backend.name() == 'sqlite':
if backend.name == 'sqlite':
return SQLite_DateTime(expression)
return super().sql_cast(expression)
@@ -145,7 +145,7 @@ class Time(FormatMixin, Field):
return value
def sql_cast(self, expression):
if backend.name() == 'sqlite':
if backend.name == 'sqlite':
return SQLite_Time(expression)
return super(Time, self).sql_cast(expression)
+1 -1
View File
@@ -69,7 +69,7 @@ class Dict(Field):
return column
def _domain_value(self, operator, value):
if backend.name() == 'sqlite' and isinstance(value, bool):
if backend.name == 'sqlite' and isinstance(value, bool):
# json_extract returns 0 for JSON false and 1 for JSON true
value = int(value)
if isinstance(value, (Select, CombiningQuery)):
-3
View File
@@ -8,7 +8,6 @@ from sql import (operators, Column, Literal, Select, CombiningQuery, Null,
from sql.conditionals import Coalesce, NullIf
from sql.operators import Concat
from trytond import backend
from trytond.pyson import PYSON, PYSONEncoder, PYSONDecoder, Eval
from trytond.const import OPERATORS
from trytond.tools.string_ import StringPartitioned, LazyString
@@ -18,8 +17,6 @@ from trytond.cache import LRUDictTransaction
from ...rpc import RPC
Database = backend.get('Database')
def domain_validate(value):
assert isinstance(value, list), 'domain must be a list'
+2 -2
View File
@@ -24,7 +24,7 @@ class Numeric(Float):
def sql_column(self, table):
column = super(Numeric, self).sql_column(table)
db_type = backend.name()
db_type = backend.name
if db_type == 'sqlite':
# Must be casted as Decimal is stored as bytes
column = SQLite_Cast(column, self.sql_type().base)
@@ -32,7 +32,7 @@ class Numeric(Float):
def _domain_value(self, operator, value):
value = super(Numeric, self)._domain_value(operator, value)
db_type = backend.name()
db_type = backend.name
if db_type == 'sqlite':
if isinstance(value, (Select, CombiningQuery)):
return value
+7 -13
View File
@@ -209,13 +209,11 @@ class ModelSQL(ModelStorage):
@classmethod
def __table_handler__(cls, module_name=None, history=False):
TableHandler = backend.get('TableHandler')
return TableHandler(cls, module_name, history=history)
return backend.TableHandler(cls, module_name, history=history)
@classmethod
def __register__(cls, module_name):
cursor = Transaction().connection.cursor()
TableHandler = backend.get('TableHandler')
super(ModelSQL, cls).__register__(module_name)
if callable(cls.table_query):
@@ -268,8 +266,8 @@ class ModelSQL(ModelStorage):
and not callable(ref_model.table_query)):
ref = ref_model._table
# Create foreign key table if missing
if not TableHandler.table_exist(ref):
TableHandler(ref_model)
if not backend.TableHandler.table_exist(ref):
backend.TableHandler(ref_model)
else:
ref = None
if field_name in ['create_uid', 'write_uid']:
@@ -338,7 +336,6 @@ class ModelSQL(ModelStorage):
def __raise_integrity_error(
cls, exception, values, field_names=None, transaction=None):
pool = Pool()
TableHandler = backend.get('TableHandler')
if field_names is None:
field_names = list(cls._fields.keys())
if transaction is None:
@@ -356,7 +353,7 @@ class ModelSQL(ModelStorage):
gettext('ir.msg_required_validation_record',
**cls.__names__(field_name)))
for name, _, error in cls._sql_constraints:
if TableHandler.convert_name(name) in str(exception):
if backend.TableHandler.convert_name(name) in str(exception):
raise SQLConstraintError(gettext(error))
# Check foreign key in last because this can raise false positive
# if the target is created during the same transaction.
@@ -555,7 +552,6 @@ class ModelSQL(ModelStorage):
@classmethod
@no_table_query
def create(cls, vlist):
DatabaseIntegrityError = backend.get('DatabaseIntegrityError')
transaction = Transaction()
cursor = transaction.connection.cursor()
pool = Pool()
@@ -626,7 +622,7 @@ class ModelSQL(ModelStorage):
[insert_values]))
id_new = transaction.database.lastid(cursor)
new_ids.append(id_new)
except DatabaseIntegrityError as exception:
except backend.DatabaseIntegrityError as exception:
transaction = Transaction()
with Transaction().new_transaction(), \
Transaction().set_context(_check_access=False):
@@ -929,7 +925,6 @@ class ModelSQL(ModelStorage):
@classmethod
@no_table_query
def write(cls, records, values, *args):
DatabaseIntegrityError = backend.get('DatabaseIntegrityError')
transaction = Transaction()
cursor = transaction.connection.cursor()
pool = Pool()
@@ -982,7 +977,7 @@ class ModelSQL(ModelStorage):
try:
cursor.execute(*table.update(columns, update_values,
where=red_sql))
except DatabaseIntegrityError as exception:
except backend.DatabaseIntegrityError as exception:
transaction = Transaction()
with Transaction().new_transaction(), \
Transaction().set_context(_check_access=False):
@@ -1021,7 +1016,6 @@ class ModelSQL(ModelStorage):
@classmethod
@no_table_query
def delete(cls, records):
DatabaseIntegrityError = backend.get('DatabaseIntegrityError')
transaction = Transaction()
cursor = transaction.connection.cursor()
pool = Pool()
@@ -1134,7 +1128,7 @@ class ModelSQL(ModelStorage):
try:
cursor.execute(*table.delete(where=red_sql))
except DatabaseIntegrityError as exception:
except backend.DatabaseIntegrityError as exception:
transaction = Transaction()
with Transaction().new_transaction():
cls.__raise_integrity_error(
+2 -3
View File
@@ -350,15 +350,14 @@ def load_modules(
def _load_modules(update):
global res
TableHandler = backend.get('TableHandler')
transaction = Transaction()
with transaction.connection.cursor() as cursor:
# Migration from 3.6: remove double module
old_table = 'ir_module_module'
new_table = 'ir_module'
if TableHandler.table_exist(old_table):
TableHandler.table_rename(old_table, new_table)
if backend.TableHandler.table_exist(old_table):
backend.TableHandler.table_rename(old_table, new_table)
# Migration from 4.0: rename installed to activated
cursor.execute(*ir_module.select(ir_module.name,
+4 -9
View File
@@ -49,11 +49,9 @@ def rpc(request, database_name):
def login(request, database_name, user, parameters, language=None):
Database = backend.get('Database')
DatabaseOperationalError = backend.get('DatabaseOperationalError')
try:
Database(database_name).connect()
except DatabaseOperationalError:
backend.Database(database_name).connect()
except backend.DatabaseOperationalError:
logger.error('fail to connect to %s', database_name, exc_info=True)
abort(HTTPStatus.NOT_FOUND)
context = {
@@ -95,9 +93,8 @@ def options(request, path):
def db_exist(request, database_name):
Database = backend.get('Database')
try:
Database(database_name).connect()
backend.Database(database_name).connect()
return True
except Exception:
return False
@@ -143,8 +140,6 @@ def help_method(request, pool):
@app.auth_required
@with_pool
def _dispatch(request, pool, *args, **kwargs):
DatabaseOperationalError = backend.get('DatabaseOperationalError')
obj, method = get_object_method(request, pool)
if method in obj.__rpc__:
rpc = obj.__rpc__[method]
@@ -192,7 +187,7 @@ def _dispatch(request, pool, *args, **kwargs):
else:
result = [rpc.result(meth(i, *c_args, **c_kwargs))
for i in inst]
except DatabaseOperationalError:
except backend.DatabaseOperationalError:
if count and not rpc.readonly:
transaction.rollback()
continue
+1 -2
View File
@@ -139,7 +139,6 @@ def with_transaction(readonly=None, user=0, context=None):
@wraps(func)
def wrapper(request, pool, *args, **kwargs):
nonlocal user, context
DatabaseOperationalError = backend.get('DatabaseOperationalError')
readonly_ = readonly # can not modify non local
if readonly_ is None:
if request.method in {'POST', 'PUT', 'DELETE', 'PATCH'}:
@@ -162,7 +161,7 @@ def with_transaction(readonly=None, user=0, context=None):
context=context) as transaction:
try:
result = func(request, pool, *args, **kwargs)
except DatabaseOperationalError:
except backend.DatabaseOperationalError:
if count and not readonly_:
transaction.rollback()
continue
+5 -10
View File
@@ -25,7 +25,6 @@ def _get_remote_addr(context):
def login(dbname, loginname, parameters, cache=True, context=None):
DatabaseOperationalError = backend.get('DatabaseOperationalError')
for count in range(config.getint('database', 'retry'), -1, -1):
with Transaction().start(dbname, 0, context=context) as transaction:
pool = _get_pool(dbname)
@@ -33,7 +32,7 @@ def login(dbname, loginname, parameters, cache=True, context=None):
try:
user_id = User.get_login(loginname, parameters)
break
except DatabaseOperationalError:
except backend.DatabaseOperationalError:
if count:
continue
raise
@@ -58,7 +57,6 @@ def login(dbname, loginname, parameters, cache=True, context=None):
def logout(dbname, user, session, context=None):
DatabaseOperationalError = backend.get('DatabaseOperationalError')
for count in range(config.getint('database', 'retry'), -1, -1):
with Transaction().start(dbname, 0, context=context):
pool = _get_pool(dbname)
@@ -66,7 +64,7 @@ def logout(dbname, user, session, context=None):
try:
name = Session.remove(session)
break
except DatabaseOperationalError:
except backend.DatabaseOperationalError:
if count:
continue
raise
@@ -79,7 +77,6 @@ def logout(dbname, user, session, context=None):
def check(dbname, user, session, context=None):
DatabaseOperationalError = backend.get('DatabaseOperationalError')
for count in range(config.getint('database', 'retry'), -1, -1):
with Transaction().start(dbname, user, context=context) as transaction:
pool = _get_pool(dbname)
@@ -87,7 +84,7 @@ def check(dbname, user, session, context=None):
try:
find = Session.check(user, session)
break
except DatabaseOperationalError:
except backend.DatabaseOperationalError:
if count:
continue
raise
@@ -108,7 +105,6 @@ def check(dbname, user, session, context=None):
def check_timeout(dbname, user, session, context=None):
DatabaseOperationalError = backend.get('DatabaseOperationalError')
for count in range(config.getint('database', 'retry'), -1, -1):
with Transaction().start(dbname, user, context=context) as transaction:
pool = _get_pool(dbname)
@@ -116,7 +112,7 @@ def check_timeout(dbname, user, session, context=None):
try:
valid = Session.check_timeout(user, session)
break
except DatabaseOperationalError:
except backend.DatabaseOperationalError:
if count:
continue
raise
@@ -129,11 +125,10 @@ def check_timeout(dbname, user, session, context=None):
def reset(dbname, session, context):
DatabaseOperationalError = backend.get('DatabaseOperationalError')
try:
with Transaction().start(dbname, 0, context=context):
pool = _get_pool(dbname)
Session = pool.get('ir.session')
Session.reset(session)
except DatabaseOperationalError:
except backend.DatabaseOperationalError:
logger.debug('Reset session failed', exc_info=True)
+1 -1
View File
@@ -36,7 +36,7 @@ config.update_etc(opt.config)
# Import after application is configured
from trytond import backend
if backend.name() == 'sqlite':
if backend.name == 'sqlite':
database_name = ':memory:'
else:
database_name = 'test_' + str(int(time.time()))
+2 -2
View File
@@ -107,14 +107,14 @@ class BusTestCase(unittest.TestCase):
"Test notify"
notify("Test", "Message", user=1)
@unittest.skipIf(backend.name() == 'sqlite', 'SQLite has not channel')
@unittest.skipIf(backend.name == 'sqlite', 'SQLite has not channel')
def test_subscribe_nothing(self):
"Test subscribe with nothing"
response = Bus.subscribe(DB_NAME, ['user:1'])
self.assertEqual(response, {'message': None, 'channel': None})
@unittest.skipIf(backend.name() == 'sqlite', 'SQLite has not channel')
@unittest.skipIf(backend.name == 'sqlite', 'SQLite has not channel')
def test_subscribe_message(self):
"Test subscribe with message"
Bus.subscribe(DB_NAME, ['user:1'])
+1 -1
View File
@@ -157,7 +157,7 @@ class MemoryCacheTestCase(unittest.TestCase):
self.assertEqual(cache_expire.get('foo'), None)
@unittest.skipIf(backend.name() == 'sqlite', "SQLite has not channel")
@unittest.skipIf(backend.name == 'sqlite', "SQLite has not channel")
class MemoryCacheChannelTestCase(MemoryCacheTestCase):
"Test Cache with channel"
+2 -3
View File
@@ -514,11 +514,10 @@ class UnaccentedTestCase(unittest.TestCase):
@classmethod
def _clear_unaccent_cache(cls):
Database = backend.get('Database')
Database._has_unaccent.clear()
backend.Database._has_unaccent.clear()
@unittest.skipUnless(backend.name() == 'postgresql',
@unittest.skipUnless(backend.name == 'postgresql',
"unaccent works only on postgresql")
class FieldCharUnaccentedTestCase(UnaccentedTestCase):
"Test Field Char with unaccented searches"
+7 -10
View File
@@ -146,12 +146,11 @@ class FieldDictTestCase(unittest.TestCase):
@with_transaction()
@unittest.skipIf(
backend.name() != 'postgresql', 'jsonb only supported by postgresql')
backend.name != 'postgresql', 'jsonb only supported by postgresql')
def test_create_jsonb(self):
"Test create dict as jsonb"
connection = Transaction().connection
Database = backend.get('Database')
if Database().get_version(connection) < (9, 2):
if backend.Database().get_version(connection) < (9, 2):
return
Dict = Pool().get('test.dict_jsonb')
@@ -194,12 +193,11 @@ class FieldDictTestCase(unittest.TestCase):
@with_transaction()
@unittest.skipIf(
backend.name() != 'postgresql', 'jsonb only supported by postgresql')
backend.name != 'postgresql', 'jsonb only supported by postgresql')
def test_write_jsonb(self):
"Test write dict as jsonb"
connection = Transaction().connection
Database = backend.get('Database')
if Database().get_version(connection) < (9, 2):
if backend.Database().get_version(connection) < (9, 2):
return
Dict = Pool().get('test.dict_jsonb')
@@ -690,12 +688,11 @@ class FieldDictTestCase(unittest.TestCase):
@with_transaction()
@unittest.skipIf(
backend.name() != 'postgresql', 'jsonb only supported by postgresql')
backend.name != 'postgresql', 'jsonb only supported by postgresql')
def test_search_element_jsonb(self):
"Test search dict element on jsonb"
connection = Transaction().connection
Database = backend.get('Database')
if Database().get_version(connection) < (9, 2):
if backend.Database().get_version(connection) < (9, 2):
return
pool = Pool()
@@ -750,7 +747,7 @@ class FieldDictTestCase(unittest.TestCase):
dict_.dico_string_keys, {'a': 'A', 'type': "Type"})
@unittest.skipUnless(backend.name() == 'postgresql',
@unittest.skipUnless(backend.name == 'postgresql',
"unaccent works only on postgresql")
class FieldDictUnaccentedTestCase(UnaccentedTestCase):
"Test Field Dict with unaccented searched"
+2 -3
View File
@@ -321,7 +321,7 @@ class FieldMultiSelectionTestCase(unittest.TestCase):
@unittest.skipIf(
backend.name() != 'postgresql', 'jsonb only supported by postgresql')
backend.name != 'postgresql', 'jsonb only supported by postgresql')
class FieldMultiSelectionJSONBTestCase(FieldMultiSelectionTestCase):
@classmethod
@@ -333,8 +333,7 @@ class FieldMultiSelectionJSONBTestCase(FieldMultiSelectionTestCase):
@with_transaction()
def setup_model(cls):
connection = Transaction().connection
Database = backend.get('Database')
if Database().get_version(connection) < (9, 2):
if backend.Database().get_version(connection) < (9, 2):
return
pool = Pool()
for model in ['test.multi_selection', 'test.multi_selection_required']:
+3 -3
View File
@@ -76,7 +76,7 @@ class HistoryTestCase(unittest.TestCase):
with self.assertRaises(AccessError):
History.read([history_id], ['value'])
@unittest.skipUnless(backend.name() == 'postgresql',
@unittest.skipUnless(backend.name == 'postgresql',
'CURRENT_TIMESTAMP as transaction_timestamp is specific to postgresql')
@with_transaction()
def test_read_same_timestamp(self):
@@ -218,7 +218,7 @@ class HistoryTestCase(unittest.TestCase):
history = History(history_id)
self.assertEqual(history.value, 1)
@unittest.skipUnless(backend.name() == 'postgresql',
@unittest.skipUnless(backend.name == 'postgresql',
'CURRENT_TIMESTAMP as transaction_timestamp is specific to postgresql')
@with_transaction()
def test_restore_history_same_timestamp(self):
@@ -314,7 +314,7 @@ class HistoryTestCase(unittest.TestCase):
self.assertEqual(records, instances)
transaction.rollback()
@unittest.skipUnless(backend.name() == 'postgresql',
@unittest.skipUnless(backend.name == 'postgresql',
'CURRENT_TIMESTAMP as transaction_timestamp is specific to postgresql')
@with_transaction()
def test_ordered_search_same_timestamp(self):
+4 -5
View File
@@ -248,7 +248,7 @@ class ModelSQLTestCase(unittest.TestCase):
}],
}])
@unittest.skipIf(backend.name() == 'sqlite',
@unittest.skipIf(backend.name == 'sqlite',
'SQLite not concerned because tryton don\'t set "NOT NULL"'
'constraint: "ALTER TABLE" don\'t support NOT NULL constraint'
'without default value')
@@ -289,7 +289,7 @@ class ModelSQLTestCase(unittest.TestCase):
timestamp = ModelsqlTimestamp.read([record.id],
['_timestamp'])[0]['_timestamp']
if backend.name() == 'sqlite':
if backend.name == 'sqlite':
# timestamp precision of sqlite is the second
time.sleep(1)
@@ -491,14 +491,13 @@ class ModelSQLTestCase(unittest.TestCase):
with self.assertRaises(SQLConstraintError):
Model.create([{'value': 42}, {'value': 42}])
@unittest.skipIf(backend.name() == 'sqlite',
@unittest.skipIf(backend.name == 'sqlite',
'SQLite does not have lock at table level but on file')
@with_transaction()
def test_lock(self):
"Test lock"
pool = Pool()
Model = pool.get('test.modelsql.lock')
DatabaseOperationalError = backend.get('DatabaseOperationalError')
transaction = Transaction()
record_id = Model.create([{}])[0].id
transaction.commit()
@@ -508,7 +507,7 @@ class ModelSQLTestCase(unittest.TestCase):
record.lock()
with transaction.new_transaction():
record = Model(record_id)
with self.assertRaises(DatabaseOperationalError):
with self.assertRaises(backend.DatabaseOperationalError):
record.lock()
+16 -22
View File
@@ -86,12 +86,11 @@ def activate_module(modules):
def restore_db_cache(name):
result = False
if DB_CACHE:
backend_name = backend.name()
cache_file = _db_cache_file(DB_CACHE, name, backend_name)
cache_file = _db_cache_file(DB_CACHE, name)
if os.path.exists(cache_file):
if backend_name == 'sqlite':
if backend.name == 'sqlite':
result = _sqlite_copy(cache_file, restore=True)
elif backend_name == 'postgresql':
elif backend.name == 'postgresql':
result = _pg_restore(cache_file)
if result:
Pool(DB_NAME).init()
@@ -102,17 +101,16 @@ def backup_db_cache(name):
if DB_CACHE:
if not os.path.exists(DB_CACHE):
os.makedirs(DB_CACHE)
backend_name = backend.name()
cache_file = _db_cache_file(DB_CACHE, name, backend_name)
cache_file = _db_cache_file(DB_CACHE, name)
if not os.path.exists(cache_file):
if backend_name == 'sqlite':
if backend.name == 'sqlite':
_sqlite_copy(cache_file)
elif backend_name == 'postgresql':
elif backend.name == 'postgresql':
_pg_dump(cache_file)
def _db_cache_file(path, name, backend_name):
return os.path.join(path, '%s-%s.dump' % (name, backend_name))
def _db_cache_file(path, name):
return os.path.join(path, '%s-%s.dump' % (name, backend.name))
def _sqlite_copy(file_, restore=False):
@@ -164,7 +162,7 @@ def _pg_restore(cache_file):
return not subprocess.call(cmd, env=env)
except OSError:
cache_name, _ = os.path.splitext(os.path.basename(cache_file))
cache_name = backend.get('TableHandler').convert_name(cache_name)
cache_name = backend.TableHandler.convert_name(cache_name)
with Transaction().start(
None, 0, close=True, autocommit=True) as transaction:
transaction.database.drop(transaction.connection, DB_NAME)
@@ -182,9 +180,9 @@ def _pg_dump(cache_file):
return not subprocess.call(cmd, env=env)
except OSError:
cache_name, _ = os.path.splitext(os.path.basename(cache_file))
cache_name = backend.get('TableHandler').convert_name(cache_name)
cache_name = backend.TableHandler.convert_name(cache_name)
# Ensure any connection is left open
backend.get('Database')(DB_NAME).close()
backend.Database(DB_NAME).close()
with Transaction().start(
None, 0, close=True, autocommit=True) as transaction:
transaction.database.create(
@@ -698,15 +696,13 @@ class ModuleTestCase(unittest.TestCase):
def db_exist(name=DB_NAME):
Database = backend.get('Database')
database = Database().connect()
database = backend.Database().connect()
return name in database.list()
def create_db(name=DB_NAME, lang='en'):
Database = backend.get('Database')
if not db_exist(name):
database = Database()
database = backend.Database()
database.connect()
connection = database.get_connection(autocommit=True)
try:
@@ -714,7 +710,7 @@ def create_db(name=DB_NAME, lang='en'):
finally:
database.put_connection(connection, True)
database = Database(name)
database = backend.Database(name)
connection = database.get_connection()
try:
with connection.cursor() as cursor:
@@ -744,8 +740,7 @@ def create_db(name=DB_NAME, lang='en'):
def drop_db(name=DB_NAME):
if db_exist(name):
Database = backend.get('Database')
database = Database(name)
database = backend.Database(name)
database.close()
with Transaction().start(
@@ -774,12 +769,11 @@ doctest_checker = doctest.OutputChecker()
class TestSuite(unittest.TestSuite):
def run(self, *args, **kwargs):
DatabaseOperationalError = backend.get('DatabaseOperationalError')
while True:
try:
exist = db_exist()
break
except DatabaseOperationalError as err:
except backend.DatabaseOperationalError as err:
# Retry on connection error
sys.stderr.write(str(err))
time.sleep(1)
+1 -2
View File
@@ -17,8 +17,7 @@ def migrate_property(
pool = Pool()
Field = pool.get('ir.model.field')
Model = pool.get('ir.model')
TableHandler = backend.get('TableHandler')
if not TableHandler.table_exist('ir_property'):
if not backend.TableHandler.table_exist('ir_property'):
return
cursor = Transaction().connection.cursor()
field = Field.__table__()
+3 -4
View File
@@ -91,7 +91,6 @@ class Transaction(object):
'''
Start transaction
'''
Database = backend.get('Database')
assert self.user is None
assert self.database is None
assert self.close is None
@@ -101,10 +100,10 @@ class Transaction(object):
# but it may be also before transactions started before
self.started_at = self.monotonic_time()
if not database_name:
database = Database().connect()
database = backend.Database().connect()
else:
database = Database(database_name).connect()
Flavor.set(Database.flavor)
database = backend.Database(database_name).connect()
Flavor.set(backend.Database.flavor)
self.connection = database.get_connection(readonly=readonly,
autocommit=autocommit)
self.user = user
+3 -5
View File
@@ -15,13 +15,11 @@ from trytond.transaction import Transaction
__all__ = ['work']
logger = logging.getLogger(__name__)
Database = backend.get('Database')
DatabaseOperationalError = backend.get('DatabaseOperationalError')
class Queue(object):
def __init__(self, pool, mpool):
self.database = Database(pool.database_name).connect()
self.database = backend.Database(pool.database_name).connect()
self.connection = self.database.get_connection(autocommit=True)
self.pool = pool
self.mpool = mpool
@@ -44,7 +42,7 @@ class TaskList(list):
def work(options):
Flavor.set(Database.flavor)
Flavor.set(backend.Database.flavor)
if not config.getboolean('queue', 'worker', default=False):
return
try:
@@ -113,7 +111,7 @@ def run_task(pool, task_id):
break
task.run()
break
except DatabaseOperationalError:
except backend.DatabaseOperationalError:
if count:
transaction.rollback()
continue