diff --git a/addons/base_import_module/models/ir_module.py b/addons/base_import_module/models/ir_module.py index 67484eb9104..02373f6ebb3 100644 --- a/addons/base_import_module/models/ir_module.py +++ b/addons/base_import_module/models/ir_module.py @@ -83,7 +83,7 @@ class IrModule(models.Model): noupdate = True pathname = opj(path, filename) idref = {} - convert_file(self.env.cr, module, filename, idref, mode=mode, noupdate=noupdate, kind=kind, pathname=pathname) + convert_file(self.env, module, filename, idref, mode=mode, noupdate=noupdate, kind=kind, pathname=pathname) path_static = opj(path, 'static') IrAttachment = self.env['ir.attachment'] diff --git a/addons/mail/models/template_reset_mixin.py b/addons/mail/models/template_reset_mixin.py index 2200f7321ad..f8735d6e3bb 100644 --- a/addons/mail/models/template_reset_mixin.py +++ b/addons/mail/models/template_reset_mixin.py @@ -99,7 +99,7 @@ class TemplateResetMixin(models.AbstractModel): # We don't have a way to pass context while loading record from a file, so we use this hack # to pass the context key that is needed to reset the fields not available in data file rec.set('context', json.dumps({'reset_template': 'True'})) - obj = xml_import(template.env.cr, module, {}, mode='init', xml_filename=fullpath) + obj = xml_import(template.env, module, {}, mode='init', xml_filename=fullpath) obj._tag_record(rec) template._override_translation_term(module, [xml_id, external_id]) else: diff --git a/addons/mail/tests/test_mail_template.py b/addons/mail/tests/test_mail_template.py index 5dd24f6e94f..14b0ffdaf75 100644 --- a/addons/mail/tests/test_mail_template.py +++ b/addons/mail/tests/test_mail_template.py @@ -152,7 +152,7 @@ class TestMailTemplate(MailCommon): class TestMailTemplateReset(MailCommon): def _load(self, module, *args): - convert_file(self.cr, module='mail', + convert_file(self.env, module='mail', filename=get_module_resource(module, *args), idref={}, mode='init', noupdate=False, kind='test') diff --git a/addons/point_of_sale/wizard/pos_session_check_product_wizard.py b/addons/point_of_sale/wizard/pos_session_check_product_wizard.py index 03fcd58e8e3..82caa30aeb5 100644 --- a/addons/point_of_sale/wizard/pos_session_check_product_wizard.py +++ b/addons/point_of_sale/wizard/pos_session_check_product_wizard.py @@ -10,7 +10,7 @@ class PosSessionCheckProductWizard(models.TransientModel): _description = 'Verify if there are any products for the PoS' def load_demo_products(self): - convert.convert_file(self.env.cr, 'point_of_sale', 'data/point_of_sale_onboarding.xml', None, mode='init', kind='data') + convert.convert_file(self.env, 'point_of_sale', 'data/point_of_sale_onboarding.xml', None, mode='init', kind='data') return self.open_ui() def open_ui(self): diff --git a/addons/sms/tests/test_sms_template.py b/addons/sms/tests/test_sms_template.py index cc278899514..20578723978 100644 --- a/addons/sms/tests/test_sms_template.py +++ b/addons/sms/tests/test_sms_template.py @@ -114,7 +114,7 @@ class TestSmsTemplateAccessRights(TransactionCase): class TestSMSTemplateReset(TransactionCase): def _load(self, module, *args): - convert_file(self.cr, module='sms', + convert_file(self.env, module='sms', filename=get_module_resource(module, *args), idref={}, mode='init', noupdate=False, kind='test') diff --git a/addons/test_website/tests/test_qweb.py b/addons/test_website/tests/test_qweb.py index 2d5c40e4f99..aab35f16da1 100644 --- a/addons/test_website/tests/test_qweb.py +++ b/addons/test_website/tests/test_qweb.py @@ -12,7 +12,7 @@ from odoo.modules.module import get_module_resource class TestQweb(TransactionCaseWithUserDemo): def _load(self, module, *args): tools.convert_file( - self.cr, 'test_website', + self.env, 'test_website', get_module_resource(module, *args), {}, 'init', False, 'test' ) diff --git a/odoo/addons/base/models/ir_demo.py b/odoo/addons/base/models/ir_demo.py index e7ee63874ef..5f53c28e799 100644 --- a/odoo/addons/base/models/ir_demo.py +++ b/odoo/addons/base/models/ir_demo.py @@ -13,7 +13,7 @@ class IrDemo(models.TransientModel): @assert_log_admin_access def install_demo(self): - force_demo(self.env.cr) + force_demo(self.env) return { 'type': 'ir.actions.act_url', 'target': 'self', diff --git a/odoo/addons/test_convert/tests/test_convert.py b/odoo/addons/test_convert/tests/test_convert.py index fb8d380cab6..9d9dd9c0091 100644 --- a/odoo/addons/test_convert/tests/test_convert.py +++ b/odoo/addons/test_convert/tests/test_convert.py @@ -77,7 +77,7 @@ class TestEvalXML(common.TransactionCase): self.eval_xml(Field('test_nofile.txt', type='file'), obj) def test_function(self): - obj = xml_import(self.cr, 'test_convert', None, 'init') + obj = xml_import(self.env, 'test_convert', None, 'init') # pass args in eval xml = E.function( @@ -126,7 +126,7 @@ class TestEvalXML(common.TransactionCase): self.assertEqual(kwargs, {}) def test_function_kwargs(self): - obj = xml_import(self.cr, 'test_convert', None, 'init') + obj = xml_import(self.env, 'test_convert', None, 'init') # pass args and kwargs in child elements xml = E.function( @@ -175,7 +175,7 @@ class TestEvalXML(common.TransactionCase): self.assertEqual(kwargs, {}) def test_function_function(self): - obj = xml_import(self.cr, 'test_convert', None, 'init') + obj = xml_import(self.env, 'test_convert', None, 'init') xml = E.function( E.function(model="test_convert.usered", name="search", eval="[[]]"), @@ -210,7 +210,7 @@ class TestEvalXML(common.TransactionCase): """.strip()) - obj = xml_import(self.cr, 'test_convert', None, 'init') + obj = xml_import(self.env, 'test_convert', None, 'init') obj._tag_record(xml) # check that field 'usered_ids' is not passed diff --git a/odoo/addons/test_convert/tests/test_env.py b/odoo/addons/test_convert/tests/test_env.py index 1e549ce3db3..ebe8e1cd812 100644 --- a/odoo/addons/test_convert/tests/test_env.py +++ b/odoo/addons/test_convert/tests/test_env.py @@ -21,7 +21,7 @@ function = E.function class TestEnv(common.TransactionCase): def setUp(self): super().setUp() - self._importer = xml_import(self.env.cr, 'test_convert', None, 'init') + self._importer = xml_import(self.env, 'test_convert', None, 'init') def importer(self, doc): etree.RelaxNG( diff --git a/odoo/modules/loading.py b/odoo/modules/loading.py index a359a7b8023..1cbd8f049bb 100644 --- a/odoo/modules/loading.py +++ b/odoo/modules/loading.py @@ -23,7 +23,7 @@ _logger = logging.getLogger(__name__) _test_logger = logging.getLogger('odoo.tests') -def load_data(cr, idref, mode, kind, package): +def load_data(env, idref, mode, kind, package): """ kind: data, demo, test, init_xml, update_xml, demo_xml. @@ -68,14 +68,14 @@ def load_data(cr, idref, mode, kind, package): noupdate = False if kind in ('demo', 'demo_xml') or (filename.endswith('.csv') and kind in ('init', 'init_xml')): noupdate = True - tools.convert_file(cr, package.name, filename, idref, mode, noupdate, kind) + tools.convert_file(env, package.name, filename, idref, mode, noupdate, kind) finally: if kind in ('demo', 'test'): threading.current_thread().testing = False return bool(filename) -def load_demo(cr, package, idref, mode): +def load_demo(env, package, idref, mode): """ Loads demo data for the specified package. """ @@ -85,8 +85,8 @@ def load_demo(cr, package, idref, mode): try: if package.data.get('demo') or package.data.get('demo_xml'): _logger.info("Module %s: loading demo", package.name) - with cr.savepoint(flush=False): - load_data(cr, idref, mode, kind='demo', package=package) + with env.cr.savepoint(flush=False): + load_data(env, idref, mode, kind='demo', package=package) return True except Exception as e: # If we could not install demo data for this module @@ -94,7 +94,6 @@ def load_demo(cr, package, idref, mode): "Module %s demo data failed to install, installed without demo data", package.name, exc_info=True) - env = api.Environment(cr, SUPERUSER_ID, {}) todo = env.ref('base.demo_failure_todo', raise_if_not_found=False) Failure = env.get('ir.demo_failure') if todo and Failure is not None: @@ -103,27 +102,26 @@ def load_demo(cr, package, idref, mode): return False -def force_demo(cr): +def force_demo(env): """ Forces the `demo` flag on all modules, and installs demo data for all installed modules. """ graph = odoo.modules.graph.Graph() - cr.execute('UPDATE ir_module_module SET demo=True') - cr.execute( + env.cr.execute('UPDATE ir_module_module SET demo=True') + env.cr.execute( "SELECT name FROM ir_module_module WHERE state IN ('installed', 'to upgrade', 'to remove')" ) - module_list = [name for (name,) in cr.fetchall()] - graph.add_modules(cr, module_list, ['demo']) + module_list = [name for (name,) in env.cr.fetchall()] + graph.add_modules(env.cr, module_list, ['demo']) for package in graph: - load_demo(cr, package, {}, 'init') + load_demo(env, package, {}, 'init') - env = api.Environment(cr, SUPERUSER_ID, {}) env['ir.module.module'].invalidate_model(['demo']) env['res.groups']._update_user_groups_view() -def load_module_graph(cr, graph, status=None, perform_checks=True, +def load_module_graph(env, graph, status=None, perform_checks=True, skip_modules=None, report=None, models_to_check=None): """Migrates+Updates or Installs all module nodes from ``graph`` @@ -142,15 +140,15 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, processed_modules = [] loaded_modules = [] - registry = odoo.registry(cr.dbname) - migrations = odoo.modules.migration.MigrationManager(cr, graph) + registry = env.registry + migrations = odoo.modules.migration.MigrationManager(env.cr, graph) module_count = len(graph) _logger.info('loading %d modules...', module_count) # register, instantiate and initialize models for each modules t0 = time.time() loading_extra_query_count = odoo.sql_db.sql_counter - loading_cursor_query_count = cr.sql_log_count + loading_cursor_query_count = env.cr.sql_log_count models_updated = set() @@ -162,7 +160,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, continue module_t0 = time.time() - module_cursor_query_count = cr.sql_log_count + module_cursor_query_count = env.cr.sql_log_count module_extra_query_count = odoo.sql_db.sql_counter needs_update = ( @@ -179,10 +177,9 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, if needs_update: if not new_install: if package.name != 'base': - registry.setup_models(cr) + registry.setup_models(env.cr) migrations.migrate_module(package, 'pre') if package.name != 'base': - env = api.Environment(cr, SUPERUSER_ID, {}) env.flush_all() load_openerp_module(package.name) @@ -191,9 +188,9 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, py_module = sys.modules['odoo.addons.%s' % (module_name,)] pre_init = package.info.get('pre_init_hook') if pre_init: - getattr(py_module, pre_init)(cr) + getattr(py_module, pre_init)(env.cr) - model_names = registry.load(cr, package) + model_names = registry.load(env.cr, package) mode = 'update' if hasattr(package, 'init') or package.state == 'to install': @@ -203,8 +200,8 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, if needs_update: models_updated |= set(model_names) models_to_check -= set(model_names) - registry.setup_models(cr) - registry.init_models(cr, model_names, {'module': package.name}, new_install) + registry.setup_models(env.cr) + registry.init_models(env.cr, model_names, {'module': package.name}, new_install) elif package.state != 'to remove': # The current module has simply been loaded. The models extended by this module # and for which we updated the schema, must have their schema checked again. @@ -216,7 +213,6 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, idref = {} if needs_update: - env = api.Environment(cr, SUPERUSER_ID, {}) # Can't put this line out of the loop: ir.module.module will be # registered by init_models() above. module = env['ir.module.module'].browse(module_id) @@ -227,9 +223,9 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, if package.state == 'to upgrade': # upgrading the module information module.write(module.get_values_from_terp(package.data)) - load_data(cr, idref, mode, kind='data', package=package) - demo_loaded = package.dbdemo = load_demo(cr, package, idref, mode) - cr.execute('update ir_module_module set demo=%s where id=%s', (demo_loaded, module_id)) + load_data(env, idref, mode, kind='data', package=package) + demo_loaded = package.dbdemo = load_demo(env, package, idref, mode) + env.cr.execute('update ir_module_module set demo=%s where id=%s', (demo_loaded, module_id)) module.invalidate_model(['demo']) migrations.migrate_module(package, 'post') @@ -245,7 +241,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, if new_install: post_init = package.info.get('post_init_hook') if post_init: - getattr(py_module, post_init)(cr, registry) + getattr(py_module, post_init)(env.cr, registry) if mode == 'update': # validate the views that have not been checked yet @@ -254,14 +250,14 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, # need to commit any modification the module's installation or # update made to the schema or data so the tests can run # (separately in their own transaction) - cr.commit() + env.cr.commit() concrete_models = [model for model in model_names if not registry[model]._abstract] if concrete_models: - cr.execute(""" + env.cr.execute(""" SELECT model FROM ir_model WHERE id NOT IN (SELECT DISTINCT model_id FROM ir_model_access) AND model IN %s """, [tuple(concrete_models)]) - models = [model for [model] in cr.fetchall()] + models = [model for [model] in env.cr.fetchall()] if models: lines = [ f"The models {models} have no access rules in module {module_name}, consider adding some, like:", @@ -276,12 +272,11 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, test_time = test_queries = 0 test_results = None if tools.config.options['test_enable'] and (needs_update or not updating): - env = api.Environment(cr, SUPERUSER_ID, {}) loader = odoo.tests.loader suite = loader.make_suite([module_name], 'at_install') if suite.countTestCases(): if not needs_update: - registry.setup_models(cr) + registry.setup_models(env.cr) # Python tests env['ir.http']._clear_routing_map() # force routing map to be rebuilt @@ -292,7 +287,6 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, test_queries = odoo.sql_db.sql_counter - tests_q0 # tests may have reset the environment - env = api.Environment(cr, SUPERUSER_ID, {}) module = env['ir.module.module'].browse(module_id) if needs_update: @@ -320,7 +314,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, module_log_level, "Module %s loaded in %.2fs%s, %s queries%s", module_name, time.time() - module_t0, f' (incl. {test_time:.2f}s test)' if test_time else '', - cr.sql_log_count - module_cursor_query_count, + env.cr.sql_log_count - module_cursor_query_count, f' ({", ".join(extras)})' if extras else '' ) if test_results and not test_results.wasSuccessful(): @@ -333,7 +327,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, _logger.runbot("%s modules loaded in %.2fs, %s queries (+%s extra)", len(graph), time.time() - t0, - cr.sql_log_count - loading_cursor_query_count, + env.cr.sql_log_count - loading_cursor_query_count, odoo.sql_db.sql_counter - loading_extra_query_count) # extra queries: testes, notify, any other closed cursor return loaded_modules, processed_modules @@ -352,7 +346,7 @@ def _check_module_names(cr, module_names): incorrect_names = mod_names.difference([x['name'] for x in cr.dictfetchall()]) _logger.warning('invalid module names, ignored: %s', ", ".join(incorrect_names)) -def load_marked_modules(cr, graph, states, force, progressdict, report, +def load_marked_modules(env, graph, states, force, progressdict, report, loaded_modules, perform_checks, models_to_check=None): """Loads modules marked with ``states``, adding them to ``graph`` and ``loaded_modules`` and returns a list of installed/upgraded modules.""" @@ -362,14 +356,14 @@ def load_marked_modules(cr, graph, states, force, progressdict, report, processed_modules = [] while True: - cr.execute("SELECT name from ir_module_module WHERE state IN %s" ,(tuple(states),)) - module_list = [name for (name,) in cr.fetchall() if name not in graph] + env.cr.execute("SELECT name from ir_module_module WHERE state IN %s", (tuple(states),)) + module_list = [name for (name,) in env.cr.fetchall() if name not in graph] if not module_list: break - graph.add_modules(cr, module_list, force) + graph.add_modules(env.cr, module_list, force) _logger.debug('Updating graph with %d more modules', len(module_list)) loaded, processed = load_module_graph( - cr, graph, progressdict, report=report, skip_modules=loaded_modules, + env, graph, progressdict, report=report, skip_modules=loaded_modules, perform_checks=perform_checks, models_to_check=models_to_check ) processed_modules.extend(processed) @@ -420,8 +414,9 @@ def load_modules(registry, force_demo=False, status=None, update_module=False): # processed_modules: for cleanup step after install # loaded_modules: to avoid double loading report = registry._assertion_report + env = api.Environment(cr, SUPERUSER_ID, {}) loaded_modules, processed_modules = load_module_graph( - cr, graph, status, perform_checks=update_module, + env, graph, status, perform_checks=update_module, report=report, models_to_check=models_to_check) load_lang = tools.config.pop('load_language') @@ -435,7 +430,6 @@ def load_modules(registry, force_demo=False, status=None, update_module=False): # STEP 2: Mark other modules to be loaded/updated if update_module: - env = api.Environment(cr, SUPERUSER_ID, {}) Module = env['ir.module.module'] _logger.info('updating modules list') Module.update_list() @@ -475,11 +469,11 @@ def load_modules(registry, force_demo=False, status=None, update_module=False): previously_processed = -1 while previously_processed < len(processed_modules): previously_processed = len(processed_modules) - processed_modules += load_marked_modules(cr, graph, + processed_modules += load_marked_modules(env, graph, ['installed', 'to upgrade', 'to remove'], force, status, report, loaded_modules, update_module, models_to_check) if update_module: - processed_modules += load_marked_modules(cr, graph, + processed_modules += load_marked_modules(env, graph, ['to install'], force, status, report, loaded_modules, update_module, models_to_check) @@ -487,7 +481,6 @@ def load_modules(registry, force_demo=False, status=None, update_module=False): registry.setup_models(cr) # check that all installed modules have been loaded by the registry - env = api.Environment(cr, SUPERUSER_ID, {}) Module = env['ir.module.module'] modules = Module.search(Module._get_modules_to_load_domain(), order='name') missing = [name for name in modules.mapped('name') if name not in graph] @@ -510,7 +503,6 @@ def load_modules(registry, force_demo=False, status=None, update_module=False): # STEP 4: Finish and cleanup installations if processed_modules: - env = api.Environment(cr, SUPERUSER_ID, {}) cr.execute("SELECT model from ir_model") for (model,) in cr.fetchall(): @@ -533,7 +525,6 @@ def load_modules(registry, force_demo=False, status=None, update_module=False): cr.execute("SELECT name, id FROM ir_module_module WHERE state=%s", ('to remove',)) modules_to_remove = dict(cr.fetchall()) if modules_to_remove: - env = api.Environment(cr, SUPERUSER_ID, {}) pkgs = reversed([p for p in graph if p.name in modules_to_remove]) for pkg in pkgs: uninstall_hook = pkg.info.get('uninstall_hook') @@ -567,7 +558,6 @@ def load_modules(registry, force_demo=False, status=None, update_module=False): # STEP 6: verify custom views on every model if update_module: - env = api.Environment(cr, SUPERUSER_ID, {}) env['res.groups']._update_user_groups_view() View = env['ir.ui.view'] for model in registry: @@ -590,7 +580,6 @@ def load_modules(registry, force_demo=False, status=None, update_module=False): # management of those hooks in `Registry.setup_models`: all the calls to # setup_models() done here do not mess up with hooks, as registry.ready # is False. - env = api.Environment(cr, SUPERUSER_ID, {}) for model in env.values(): model._register_hook() env.flush_all() diff --git a/odoo/tools/convert.py b/odoo/tools/convert.py index 7eeb24beba2..cf66ba0e083 100644 --- a/odoo/tools/convert.py +++ b/odoo/tools/convert.py @@ -577,10 +577,10 @@ form: module.record_id""" % (xml_id,) def noupdate(self): return self._noupdate[-1] - def __init__(self, cr, module, idref, mode, noupdate=False, xml_filename=None): + def __init__(self, env, module, idref, mode, noupdate=False, xml_filename=None): self.mode = mode self.module = module - self.envs = [odoo.api.Environment(cr, SUPERUSER_ID, {})] + self.envs = [env] self.idref = {} if idref is None else idref self._noupdate = [noupdate] self.xml_filename = xml_filename @@ -599,27 +599,27 @@ form: module.record_id""" % (xml_id,) self._tag_root(de) DATA_ROOTS = ['odoo', 'data', 'openerp'] -def convert_file(cr, module, filename, idref, mode='update', noupdate=False, kind=None, pathname=None): +def convert_file(env, module, filename, idref, mode='update', noupdate=False, kind=None, pathname=None): if pathname is None: pathname = os.path.join(module, filename) ext = os.path.splitext(filename)[1].lower() with file_open(pathname, 'rb') as fp: if ext == '.csv': - convert_csv_import(cr, module, pathname, fp.read(), idref, mode, noupdate) + convert_csv_import(env, module, pathname, fp.read(), idref, mode, noupdate) elif ext == '.sql': - convert_sql_import(cr, fp) + convert_sql_import(env, fp) elif ext == '.xml': - convert_xml_import(cr, module, fp, idref, mode, noupdate) + convert_xml_import(env, module, fp, idref, mode, noupdate) elif ext == '.js': pass # .js files are valid but ignored here. else: raise ValueError("Can't load unknown file type %s.", filename) -def convert_sql_import(cr, fp): - cr.execute(fp.read()) # pylint: disable=sql-injection +def convert_sql_import(env, fp): + env.cr.execute(fp.read()) # pylint: disable=sql-injection -def convert_csv_import(cr, module, fname, csvcontent, idref=None, mode='init', +def convert_csv_import(env, module, fname, csvcontent, idref=None, mode='init', noupdate=False): '''Import csv file : quote: " @@ -647,14 +647,13 @@ def convert_csv_import(cr, module, fname, csvcontent, idref=None, mode='init', 'install_filename': fname, 'noupdate': noupdate, } - env = odoo.api.Environment(cr, SUPERUSER_ID, context) - result = env[model].load(fields, datas) + result = env[model].with_context(**context).load(fields, datas) if any(msg['type'] == 'error' for msg in result['messages']): # Report failed import and abort module install warning_msg = "\n".join(msg['message'] for msg in result['messages']) raise Exception(_('Module loading %s failed: file %s could not be processed:\n %s') % (module, fname, warning_msg)) -def convert_xml_import(cr, module, xmlfile, idref=None, mode='init', noupdate=False, report=None): +def convert_xml_import(env, module, xmlfile, idref=None, mode='init', noupdate=False, report=None): doc = etree.parse(xmlfile) schema = os.path.join(config['root_path'], 'import_xml.rng') relaxng = etree.RelaxNG(etree.parse(schema)) @@ -675,5 +674,5 @@ def convert_xml_import(cr, module, xmlfile, idref=None, mode='init', noupdate=Fa xml_filename = xmlfile else: xml_filename = xmlfile.name - obj = xml_import(cr, module, idref, mode, noupdate=noupdate, xml_filename=xml_filename) + obj = xml_import(env, module, idref, mode, noupdate=noupdate, xml_filename=xml_filename) obj.parse(doc.getroot())