From ac0dcf391c4eb0c3ab84f4887fd6fcceb9a0e264 Mon Sep 17 00:00:00 2001 From: eacm-odoo Date: Wed, 6 May 2026 10:16:39 -0700 Subject: [PATCH] [FIX] common: auto-import plugin `common/` submodules on load Modules placed under a plugin's `common/` directory were never imported when the plugin loaded: only the plugin package and its `commands/` were. Anything in `common/` that relied on import-time side effects (subclass registration, decorators, etc.) stayed inert, so plugin extensions could silently fail to apply depending on import order. Walk `common/` after importing the plugin and import each submodule explicitly so its side effects run. --- odev/_version.py | 2 +- odev/common/odev.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/odev/_version.py b/odev/_version.py index 1c533a3d..c11e60e8 100644 --- a/odev/_version.py +++ b/odev/_version.py @@ -22,4 +22,4 @@ # or merged change. # ------------------------------------------------------------------------------ -__version__ = "4.24.0" +__version__ = "4.24.1" diff --git a/odev/common/odev.py b/odev/common/odev.py index fb2a73d8..e066e610 100644 --- a/odev/common/odev.py +++ b/odev/common/odev.py @@ -594,6 +594,8 @@ def _register_plugin_commands(self) -> None: except ImportError as error: logger.debug(f"Could not import plugin module {plugin.path.name}: {error}") + self._import_plugin_common_modules(plugin) + for command_class in self.import_commands(plugin.path.glob("commands/**")): command_names = [command_class._name] + (list(command_class._aliases) or []) base_command_class = self.commands.get(command_class._name) @@ -620,6 +622,23 @@ class PatchedCommand(command_class, base_command_class, *base_command_class.__ba command_class.prepare_command(self) self.commands.update(dict.fromkeys(command_names, command_class)) + def _import_plugin_common_modules(self, plugin) -> None: + """Import every submodule under a plugin's `common/` directory so their + import-time side effects (subclass registration, decorators, patches) run. + """ + common_path = plugin.path / "common" + if not common_path.is_dir(): + return + + for module_info in pkgutil.iter_modules([common_path.as_posix()]): + module_name = f"odev.plugins.{plugin.path.name}.common.{module_info.name}" + if module_name in sys.modules: + continue + try: + importlib.import_module(module_name) + except ImportError as error: + logger.debug(f"Could not import common module {module_info.name} from plugin {plugin.name!r}: {error}") + def _load_config(self) -> None: """Reload the configuration file.""" self.__class__.config = Config(self.name)