#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.modules import load_modules from threading import RLock import logging class Pool(object): classes = { 'model': {}, 'wizard': {}, 'report': {}, } _lock = RLock() _locks = {} _pool = {} _pools = {} def __new__(cls, database_name): cls._lock.acquire() lock = cls._locks.setdefault(database_name, RLock()) cls._lock.release() lock.acquire() if database_name in cls._pools: res = cls._pools[database_name] lock.release() return res lock.release() return object.__new__(cls) def __init__(self, database_name): self.database_name = database_name self._lock.acquire() lock = self._locks.setdefault(database_name, RLock()) self._lock.release() lock.acquire() self._pool.setdefault(database_name, {}) for type in self.classes.keys(): self._pool[database_name].setdefault(type, {}) self._pools.setdefault(database_name, self) lock.release() self._sql_errors = {} @staticmethod def register(cls, type='model'): ''' Register a class :param cls: the class :param type: the type ''' for module in cls.__module__.split('.'): if module != 'trytond' and module != 'modules': break Pool.classes[type].setdefault(module, []).append(cls) @staticmethod def database_list(): ''' :return: database list ''' return Pool._pool.keys() def init(self, update=False, lang=None): ''' Init pool :param database_name: the database name :param update: a boolean to proceed to update :param lang: a list of language code to be updated ''' logger = logging.getLogger('pool') logger.info('init pool for "%s"' % self.database_name) self._lock.acquire() lock = self._locks.setdefault(self.database_name, RLock()) self._lock.release() lock.acquire() try: #Clean the _pool before loading modules for type in self.classes.keys(): self._pool[self.database_name][type] = {} restart = not load_modules(self.database_name, self, update=update, lang=lang) if restart: self.init() finally: lock.release() def get(self, name, type='model'): ''' Get an object from the pool :param name: the object name :param type: the type :return: the instance ''' if type == '*': for type in self.classes.keys(): if name in self._pool[self.database_name][type]: break return self._pool[self.database_name][type][name] def add(self, obj, type='model'): ''' Add an object to the pool :param obj: the object :param type: the type ''' self._pool[self.database_name][type][obj._name] = obj obj.pool = self def object_name_list(self, type='model'): ''' Return the object name list of a type :param type: the type :return: a list of name ''' if type == '*': res = [] for type in self.classes.keys(): res += self._pool[self.database_name][type].keys() return res return self._pool[self.database_name][type].keys() def instanciate(self, module): ''' Instanciate objects for a module :param: the module name :return: a dictionary with each type as key and a list of object as value ''' res = {} for _type in self.classes.keys(): res[_type] = [] for cls in self.classes[_type].get(module, []): if cls._name in self._pool[self.database_name][_type].keys(): parent_cls = self.get(cls._name, type=_type).__class__ cls = type(cls._name, (cls, parent_cls), {}) obj = object.__new__(cls) self.add(obj, type=_type) obj.__init__() res[_type].append(obj) if hasattr(obj, '_sql_constraints'): for key, _, msg in obj._sql_constraints: self._sql_errors[obj._table + '_' + key] = msg if hasattr(obj, '_sql_error_messages'): for key, msg in obj._sql_error_messages.iteritems(): self._sql_errors[obj._table + '_' + key] = msg return res