Source code for oduit.manifest_collection

# Copyright (C) 2025 The ODUIT Authors.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.

from collections.abc import Iterator

from .manifest import Manifest


[docs] class ManifestCollection: """Represents a collection of Odoo module manifests."""
[docs] def __init__(self) -> None: """Initialize an empty ManifestCollection.""" self._manifests: dict[str, Manifest] = {}
[docs] def add(self, addon_name: str, manifest: Manifest) -> None: """Add a manifest to the collection. Args: addon_name: Name of the addon manifest: Manifest instance to add """ self._manifests[addon_name] = manifest
[docs] def remove(self, addon_name: str) -> None: """Remove a manifest from the collection. Args: addon_name: Name of the addon to remove Raises: KeyError: If addon_name is not in the collection """ del self._manifests[addon_name]
[docs] def get(self, addon_name: str) -> Manifest | None: """Get a manifest by addon name. Args: addon_name: Name of the addon Returns: Manifest instance or None if not found """ return self._manifests.get(addon_name)
[docs] def __getitem__(self, addon_name: str) -> Manifest: """Get a manifest by addon name using dict-like access. Args: addon_name: Name of the addon Returns: Manifest instance Raises: KeyError: If addon_name is not in the collection """ return self._manifests[addon_name]
[docs] def __contains__(self, addon_name: str) -> bool: """Check if an addon is in the collection. Args: addon_name: Name of the addon to check Returns: True if addon exists in collection, False otherwise """ return addon_name in self._manifests
[docs] def __len__(self) -> int: """Get the number of manifests in the collection. Returns: Number of manifests """ return len(self._manifests)
[docs] def __iter__(self) -> Iterator[str]: """Iterate over addon names in the collection. Returns: Iterator over addon names """ return iter(self._manifests)
[docs] def items(self) -> Iterator[tuple[str, Manifest]]: """Get iterator over (addon_name, manifest) pairs. Returns: Iterator of tuples containing addon name and Manifest """ return iter(self._manifests.items())
[docs] def keys(self) -> Iterator[str]: """Get iterator over addon names. Returns: Iterator over addon names """ return iter(self._manifests.keys())
[docs] def values(self) -> Iterator[Manifest]: """Get iterator over manifests. Returns: Iterator over Manifest instances """ return iter(self._manifests.values())
[docs] def get_all_dependencies(self) -> set[str]: """Get all unique codependencies across all manifests in the collection. Returns: Set of all codependency names """ all_deps = set() for manifest in self._manifests.values(): all_deps.update(manifest.codependencies) return all_deps
[docs] def get_installable_addons(self) -> list[str]: """Get list of all installable addon names. Returns: List of addon names that are installable """ return [ name for name, manifest in self._manifests.items() if manifest.installable ]
[docs] def get_auto_install_addons(self) -> list[str]: """Get list of all auto-install addon names. Returns: List of addon names that are auto-installable """ return [ name for name, manifest in self._manifests.items() if manifest.auto_install ]
[docs] def filter_by_dependency(self, dependency_name: str) -> "ManifestCollection": """Create a new collection with only addons that depend on a specific module. Args: dependency_name: Name of the dependency to filter by Returns: New ManifestCollection containing only matching addons """ filtered = ManifestCollection() for name, manifest in self._manifests.items(): if manifest.has_dependency(dependency_name): filtered.add(name, manifest) return filtered
[docs] def validate_all(self) -> dict[str, list[str]]: """Validate all manifests in the collection. Returns: Dictionary mapping addon names to lists of validation warnings (only includes addons with warnings) """ issues = {} for name, manifest in self._manifests.items(): warnings = manifest.validate_structure() if warnings: issues[name] = warnings return issues
[docs] def clear(self) -> None: """Remove all manifests from the collection.""" self._manifests.clear()
[docs] def __str__(self) -> str: """String representation of the collection.""" return f"ManifestCollection({len(self._manifests)} manifests)"
[docs] def __repr__(self) -> str: """Developer representation of the collection.""" addon_list = ", ".join(sorted(self._manifests.keys())) return f"ManifestCollection([{addon_list}])"