Use direct access to backend classes
issue8836 review258421002
This commit is contained in:
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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__],
|
||||
|
||||
@@ -18,7 +18,7 @@ __all__ = [
|
||||
'SequenceType', 'Sequence', 'SequenceStrict',
|
||||
]
|
||||
|
||||
sql_sequence = backend.get('Database').has_sequence()
|
||||
sql_sequence = backend.Database.has_sequence()
|
||||
|
||||
|
||||
class AffixError(ValidationError):
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)):
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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()))
|
||||
|
||||
@@ -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'])
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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']:
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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__()
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user