def test_full(args): """ Test full install/uninstall/reinstall cycle for all modules """ with flectra.api.Environment.manage(): with flectra.registry(args.database).cursor() as cr: env = flectra.api.Environment(cr, flectra.SUPERUSER_ID, {}) def valid(module): return not (module.name in BLACKLIST or module.name.startswith(IGNORE) or module.state in ('installed', 'uninstallable')) modules = env['ir.module.module'].search([]).filtered(valid) # order modules in topological order modules = modules.browse( topological_sort({ module.id: module.dependencies_id.depend_id.ids for module in modules })) modules_todo = [(module.id, module.name) for module in modules] resume = args.resume_at skip = set(args.skip.split(',')) if args.skip else set() for module_id, module_name in modules_todo: if module_name == resume: resume = None if resume or module_name in skip: install(args.database, module_id, module_name) else: cycle(args.database, module_id, module_name)
def check_tables_exist(self, cr): """ Verify that all tables are present and try to initialize those that are missing. """ env = flectra.api.Environment(cr, SUPERUSER_ID, {}) table2model = { model._table: name for name, model in env.items() if not model._abstract } missing_tables = set(table2model).difference( existing_tables(cr, table2model)) if missing_tables: missing = {table2model[table] for table in missing_tables} _logger.warning("Models have no table: %s.", ", ".join(missing)) # recreate missing tables following model dependencies deps = {name: model._depends for name, model in env.items()} for name in topological_sort(deps): if name in missing: _logger.info("Recreate table of model %s.", name) env[name].init() # check again, and log errors if tables are still missing missing_tables = set(table2model).difference( existing_tables(cr, table2model)) for table in missing_tables: _logger.error("Model %s has no table.", table2model[table])
def check_tables_exist(self, cr): """ Verify that all tables are present and try to initialize those that are missing. """ # This monkey patch is meant to avoid that the _logger writes # warning and error messages, while running an update all, # in case the model is a bi-view-generated model. env = api.Environment(cr, SUPERUSER_ID, {}) table2model = { model._table: name for name, model in env.items() if not model._abstract and not _bi_view(name) # here is the patch } missing_tables = set(table2model).difference( existing_tables(cr, table2model)) if missing_tables: missing = {table2model[table] for table in missing_tables} _logger.warning("Models have no table: %s.", ", ".join(missing)) # recreate missing tables following model dependencies deps = {name: model._depends for name, model in env.items()} for name in topological_sort(deps): if name in missing: _logger.info("Recreate table of model %s.", name) env[name].init() # check again, and log errors if tables are still missing missing_tables = set(table2model).difference( existing_tables(cr, table2model)) for table in missing_tables: _logger.error("Model %s has no table.", table2model[table])
def modules_installed(self): Modules = self.env['ir.module.module'] domain = [('state', '=', 'installed')] modules = OrderedDict( (module.name, module.dependencies_id.mapped('name')) for module in Modules.search(domain)) sorted_modules = topological_sort(modules) return sorted_modules
def init_models(self, cr, model_names, context): """ Initialize a list of models (given by their name). Call methods ``_auto_init`` and ``init`` on each model to create or update the database tables supporting the models. The ``context`` may contain the following items: - ``module``: the name of the module being installed/updated, if any; - ``update_custom_fields``: whether custom fields should be updated. """ if 'module' in context: _logger.info('module %s: creating or updating database tables', context['module']) env = flectra.api.Environment(cr, SUPERUSER_ID, context) models = [env[model_name] for model_name in model_names] for model in models: model._auto_init() model.init() while self._post_init_queue: func = self._post_init_queue.popleft() func() if models: models[0].recompute() # make sure all tables are present table2model = { model._table: name for name, model in env.items() if not model._abstract } missing_tables = set(table2model).difference( existing_tables(cr, table2model)) if missing_tables: missing = {table2model[table] for table in missing_tables} _logger.warning("Models have no table: %s.", ", ".join(missing)) # recreate missing tables following model dependencies deps = {name: model._depends for name, model in env.items()} for name in topological_sort(deps): if name in missing: _logger.info("Recreate table of model %s.", name) env[name].init() # check again, and log errors if tables are still missing missing_tables = set(table2model).difference( existing_tables(cr, table2model)) for table in missing_tables: _logger.error("Model %s has no table.", table2model[table])
def make_nodes_xml(self, files, model, deps, WHITELIST_FIELDS, CDATA_FIELDS, XML_FIELDS): sorted_rec = topological_sort(deps) root = [] for xml_rec in sorted_rec: rec_node = self.get_xml_rec(xml_rec, WHITELIST_FIELDS, CDATA_FIELDS, XML_FIELDS) root.append(rec_node) xml_data = E.flectra(*root) fnam = os.path.join('data', '%s.xml' % model.replace('.', '_')) files.append(fnam) return (fnam, etree.tostring(xml_data, pretty_print=True, encoding='UTF-8', xml_declaration=True))
def test_topological_sort(self): random.shuffle(self.mods) modules = [(k, sample(self.mods[:i])) for i, k in enumerate(self.mods)] random.shuffle(modules) ms = dict(modules) seen = set() sorted_modules = topological_sort(ms) for module in sorted_modules: deps = ms[module] self.assertGreaterEqual( seen, set(deps), 'Module %s (index %d), ' \ 'missing dependencies %s from loaded modules %s' % ( module, sorted_modules.index(module), deps, seen )) seen.add(module)
def field_sequence(self): """ Return a function mapping a field to an integer. The value of a field is guaranteed to be strictly greater than the value of the field's dependencies. """ # map fields on their dependents dependents = { field: set(dep for dep, _ in model._field_triggers[field] if dep != field) for model in self.values() for field in model._fields.values() } # sort them topologically, and associate a sequence number to each field mapping = { field: num for num, field in enumerate(reversed(topological_sort(dependents))) } return mapping.get