ModuleManager
ModuleManager is the addon discovery and dependency-analysis API.
- class oduit.module_manager.ModuleManager(addons_path: str)[source]
Bases:
objectManages Odoo module operations and dependency resolution.
- __init__(addons_path: str)[source]
Initialize ModuleManager.
- Parameters:
addons_path – Comma-separated string of addon directory paths
- static parse_cycle_error(message: str) list[str][source]
Extract the module cycle path from an error message.
- find_module_dirs(filter_dir: str | None = None) list[str][source]
Return all module directories with __manifest__.py in configured paths
- Parameters:
filter_dir – Optional directory name to filter results. Only modules in directories with exact basename match will be returned.
- Returns:
Sorted list of module directory names
- find_modules(filter_dir: str | None = None, skip_invalid: bool = False) ManifestCollection[source]
Return all modules with manifests in configured paths as a collection
- Parameters:
filter_dir – Optional directory name to filter results. Only modules in directories with exact basename match will be returned.
skip_invalid – If True, skip modules with invalid manifests instead of raising an exception
- Returns:
ManifestCollection containing all found modules
- Raises:
ManifestError – If a manifest is invalid and skip_invalid is False
- find_module_path(module_name: str) str | None[source]
Find the absolute path to a module within addons_path and Odoo base addons
- Parameters:
module_name – Name of the module to find
- Returns:
Absolute path to module directory or None if not found
- get_manifest(module_name: str) Manifest | None[source]
Get the manifest for a module.
- Parameters:
module_name – Name of the module to get manifest for
- Returns:
Manifest instance or None if module not found
- parse_manifest(module_name: str) dict[str, Any] | None[source]
Parse and return module’s __manifest__.py content.
- Parameters:
module_name – Name of the module to parse manifest for
- Returns:
Dictionary containing manifest data or None if not found
- Raises:
ValueError – If manifest exists but contains invalid Python syntax
Note
This method is maintained for backward compatibility. Consider using get_manifest() for new code.
- get_module_codependencies(module_name: str) list[str][source]
Get codependencies from module’s manifest ‘depends’ field.
Codependencies are modules that this module depends on, meaning changes to those modules may impact this module.
- Parameters:
module_name – Name of the module to get codependencies for
- Returns:
List of codependency module names, empty list if no codependencies or module not found
- get_direct_dependencies(*module_names: str) list[str][source]
Get direct dependencies needed to install a set of modules.
Direct dependencies are the minimal set of external modules (not in the provided set) needed to install the specified modules.
- Parameters:
*module_names – One or more module names to get direct dependencies for
- Returns:
Sorted list of module names that are direct dependencies (external to the provided set) needed for installation
Example
For modules a, b, c where: - a depends on [‘b’, ‘c’] - b depends on [‘crm’] - c depends on [‘mail’] get_direct_dependencies(‘a’, ‘b’, ‘c’) returns [‘crm’, ‘mail’]
- build_dependency_graph(module_name: str) dict[str, list[str]][source]
Build complete dependency graph for a module and all its codependencies.
- Parameters:
module_name – Name of the root module to build graph for
- Returns:
Dictionary mapping each module to its direct codependencies. Format: {module_name: [list_of_codependencies]}
- Raises:
ValueError – If circular dependency is detected
- get_dependency_tree(module_name: str, max_depth: int | None = None) dict[str, Any][source]
Get hierarchical dependency tree for a module.
- Parameters:
module_name – Name of the module to get dependency tree for
max_depth – Maximum depth to traverse (None for unlimited)
- Returns:
Nested dictionary representing the dependency tree. Format: {module_name: {codependency1: {subdeps…}, codependency2: {}}}
- Raises:
ValueError – If circular dependency is detected
- get_dependencies_at_depth(module_names: list[str], max_depth: int | None = None) list[str][source]
Get all dependencies up to a specified depth for a list of modules.
- Parameters:
module_names – List of module names to get dependencies for
max_depth – Maximum depth to traverse (None for unlimited)
- Returns:
Sorted list of unique dependency names (excluding input modules)
- get_install_order(*module_names: str) list[str][source]
Get the proper installation order for one or more modules and their codependencies.
Uses topological sorting to determine the correct order for installing modules such that all codependencies are installed before the modules that depend on them.
- Parameters:
*module_names – One or more module names to get install order for
- Returns:
List of module names in the order they should be installed. Codependencies come first, then modules that depend on them.
- Raises:
ValueError – If circular dependency is detected
- analyze_dependency_cycle(*module_names: str) dict[str, Any][source]
Return structured diagnostics for the first detected dependency cycle.
- find_missing_dependencies(module_name: str) list[str][source]
Find codependencies that are not available in the addons_path.
- Parameters:
module_name – Name of the module to check codependencies for
- Returns:
List of codependency names that could not be found in addons_path. Empty list if all codependencies are available.
- Raises:
ValueError – If circular dependency is detected during graph traversal
- get_reverse_dependencies(target_module: str) list[str][source]
Get all modules that directly or indirectly depend on the target module.
This method searches through all available modules to find which ones have the target module in their codependency chain.
- Parameters:
target_module – Name of the module to find reverse dependencies for
- Returns:
List of module names that depend on the target module. Empty list if no modules depend on the target.
- detect_odoo_series() OdooSeries | None[source]
Detect the Odoo series from available modules.
Scans all available modules and attempts to detect the Odoo series from their version strings.
- Returns:
OdooSeries if detected, None if unable to detect
- get_module_version_display(module_name: str, odoo_series: OdooSeries | None = None) str[source]
Get formatted version string for display in dependency trees.
- Parameters:
module_name – Name of the module
odoo_series – Detected Odoo series (if None, will try to detect)
- Returns:
“16.0+ce” for core CE addons
”16.0+ee” for core EE addons
”1.0.2” for custom addons (actual version)
”✘ not installed” for missing addons
- Return type:
Formatted version string
- get_formatted_dependency_tree(module_name: str, max_depth: int | None = None) list[str][source]
Get formatted dependency tree for display.
- Parameters:
module_name – Name of the module to get dependency tree for
max_depth – Maximum depth to traverse (None for unlimited)
- Returns:
List of formatted lines representing the dependency tree
- sort_modules(module_names: list[str], sorting: SortingChoice | str = SortingChoice.ALPHABETICAL) list[str][source]
Sort module names according to the specified sorting method.
- Parameters:
module_names – List of module names to sort
sorting – Sorting method - either ‘alphabetical’ or ‘topological’
- Returns:
Sorted list of module names
- Raises:
ValueError – If circular dependency is detected in topological sort
Usage Examples
from oduit import ConfigLoader, ModuleManager
loader = ConfigLoader()
config = loader.load_config("dev")
manager = ModuleManager(config["addons_path"])
addons = manager.find_modules()
sale_manifest = manager.get_manifest("sale")
install_order = manager.get_install_order("sale", "purchase")
reverse_deps = manager.get_reverse_dependencies("sale")
Key Methods
find_module_dirs()andfind_modules(): discover addons fromaddons_pathfind_module_path()andget_manifest(): inspect one addonget_module_codependencies(): direct manifestdependsentries; maintained for compatibility with older namingget_direct_dependencies(): direct external dependencies for one or more target addonsget_dependency_tree()andget_formatted_dependency_tree(): dependency treesget_install_order(): dependency-resolved installation orderget_reverse_dependencies(): reverse-dependency and update impact analysisfind_missing_dependencies(): missing addon detectiondetect_odoo_series(): infer Odoo series from addon versions