### Install manifestoo-core using pip Source: https://context7.com/acsone/manifestoo-core/llms.txt Installs the manifestoo-core library using pip, the standard Python package installer. This command should be run in your terminal or command prompt. ```bash pip install manifestoo-core ``` -------------------------------- ### Handle Manifestoo Exceptions (Python) Source: https://context7.com/acsone/manifestoo-core/llms.txt The library provides a comprehensive set of custom exceptions, all inheriting from `ManifestooException`, to handle various error conditions during addon processing. This includes errors related to addon discovery, manifest parsing, and Odoo series compatibility. Example usage demonstrates robust error handling for addon processing and safe parsing of distribution names. ```python from pathlib import Path from manifestoo_core.addon import Addon from manifestoo_core.manifest import Manifest from manifestoo_core.metadata import metadata_from_addon_dir, distribution_name_to_addon_name from manifestoo_core.odoo_series import OdooSeries from manifestoo_core.exceptions import ( ManifestooException, AddonNotFound, AddonNotFoundNotADirectory, AddonNotFoundNoManifest, AddonNotFoundNoInit, AddonNotFoundNotInstallable, AddonNotFoundInvalidManifest, InvalidManifest, UnsupportedOdooSeries, UnsupportedManifestVersion, InvalidDistributionName, UnknownPostVersionStrategy, ) # Comprehensive error handling example def process_addon(addon_path: Path) -> dict: try: addon = Addon.from_addon_dir(addon_path) metadata = metadata_from_addon_dir(addon_path) return { 'name': addon.name, 'version': metadata['Version'], 'status': 'success' } except AddonNotFoundNotADirectory: return {'error': 'Path is not a directory'} except AddonNotFoundNoManifest: return {'error': 'No __manifest__.py found'} except AddonNotFoundNoInit: return {'error': 'Missing __init__.py'} except AddonNotFoundNotInstallable: return {'error': 'Addon has installable=False'} except AddonNotFoundInvalidManifest as e: return {'error': f'Invalid manifest: {e}'} except UnsupportedOdooSeries as e: return {'error': f'Unsupported Odoo version: {e}'} except UnsupportedManifestVersion as e: return {'error': f'Invalid version format: {e}'} except ManifestooException as e: return {'error': f'Unexpected error: {e}'} # Parse distribution names safely def safe_parse_dist_name(name: str) -> str: try: return distribution_name_to_addon_name(name) except InvalidDistributionName: return None ``` -------------------------------- ### Discover and Manage Addons with AddonsSet (Python) Source: https://context7.com/acsone/manifestoo-core/llms.txt The AddonsSet class allows for the discovery and management of multiple addons from specified directories. It can scan subdirectories and provides a dictionary-like interface for accessing individual addons and their metadata. Dependencies include `pathlib` and `manifestoo_core.addons_set`. ```python from pathlib import Path from manifestoo_core.addons_set import AddonsSet from manifestoo_core.odoo_series import detect_from_addons_set # Create empty addons set addons = AddonsSet() # Add addons from a single directory (scans subdirectories) addons.add_from_addons_dir(Path("/path/to/addons")) # Add from multiple directories addons.add_from_addons_dirs([ Path("/path/to/oca/sale-workflow"), Path("/path/to/oca/stock-logistics-warehouse"), Path("/path/to/custom/addons"), ]) # AddonsSet is a dict-like container print(f"Found {len(addons)} addons") print(f"Addon names: {list(addons.keys())}") print(f"String representation: {addons}") # Comma-separated sorted names # Access individual addons if 'sale_workflow_customization' in addons: addon = addons['sale_workflow_customization'] print(f"Found addon: {addon.name}") print(f"Version: {addon.manifest.version}") print(f"Path: {addon.path}") # Iterate over all addons for name, addon in addons.items(): print(f"{name}: {addon.manifest.version}") # Detect Odoo series from all addons in the set detected_series = detect_from_addons_set(addons) print(f"Detected series: {detected_series}") # Set of OdooSeries enums ``` -------------------------------- ### Addon Class Source: https://github.com/acsone/manifestoo-core/blob/main/docs/api.md The Addon class represents a concrete addon manifest, providing access to its properties and methods for loading from a directory. ```APIDOC ## Class: manifestoo_core.addon.Addon ### Description Represents a concrete addon manifest. ### Methods #### classmethod from_addon_dir(addon_dir, allow_not_installable=False) Obtain an Addon object from an addon directory path. Raises an `AddonNotFound` exception if the directory is not a valid addon directory, or if `allow_not_installable` is False and the addon is not installable. **Parameters:** - **addon_dir** (*Path*) - The directory to load the addon from. - **allow_not_installable** (*bool*) - Whether to allow addons with `installable=False`. **Returns:** - [*Addon*](#manifestoo_core.addon.Addon) - An Addon object. ### Properties - **manifest** (*Manifest*) - The addon's manifest object. - **manifest_path** (*Path*) - The path to the addon's manifest file. - **name** (*str* | None) - The addon's name. ``` -------------------------------- ### Utility Functions Source: https://github.com/acsone/manifestoo-core/blob/main/docs/api.md Utility functions for working with Odoo addons and manifests. ```APIDOC ## Functions ### manifestoo_core.addon.is_addon_dir(addon_dir, allow_not_installable=False) #### Description Detect if a directory contains an Odoo addon. #### Parameters - **addon_dir** (*Path*) - The directory to check. - **allow_not_installable** (*bool*) - Whether to allow the addon to be have installable=False in its manifest. #### Returns - *bool* - True if the directory is an Odoo addon directory, False otherwise. ### manifestoo_core.manifest.get_manifest_path(addon_dir) #### Description Get the path to the manifest file for an addon directory. Returns None if no manifest file is found. #### Parameters - **addon_dir** (*Path*) - The addon directory. #### Returns - *Path* | None - The path to the manifest file, or None if not found. ### manifestoo_core.core_addons.get_core_addon_license(addon_name, odoo_series) #### Description Get the license of a core Odoo addon. This function overrides any license set in the upstream addon manifest, as Odoo has a uniform license for each version and edition, and the manifests have been known to be unreliable in that respect. #### Parameters - **addon_name** (*str*) - The name of the core addon. - **odoo_series** (*OdooSeries*) - The Odoo series the addon belongs to. #### Returns - *str* - The license of the core Odoo addon. ``` -------------------------------- ### Query Odoo Core Addons and Licenses (Python) Source: https://context7.com/acsone/manifestoo-core/llms.txt Provides functions to identify which Odoo addons are built-in for a given series and edition. This is crucial for dependency resolution. It allows checking if an addon is core, CE-specific, or EE-specific, and retrieving its license. ```Python from manifestoo_core.core_addons import ( get_core_addons, is_core_addon, is_core_ce_addon, is_core_ee_addon, get_core_addon_license ) from manifestoo_core.odoo_series import OdooSeries series = OdooSeries.v16_0 # Get all core addons (CE + EE) for a series core_addons = get_core_addons(series) print(f"Odoo {series.value} has {len(core_addons)} core addons") print(f"Sample addons: {list(core_addons)[:5]}") # Check if specific addon is core print(f"'sale' is core: {is_core_addon('sale', series)}") print(f"'base' is core: {is_core_addon('base', series)}") print(f"'my_custom_addon' is core: {is_core_addon('my_custom_addon', series)}") # Distinguish between CE and EE addons print(f"'sale' is CE: {is_core_ce_addon('sale', series)}") print(f"'sale_subscription' is EE: {is_core_ee_addon('sale_subscription', series)}") # Get license for core addons # CE addons: LGPL-3 (AGPL-3 for v8.0) # EE addons: OEEL-1 license = get_core_addon_license('sale', series) print(f"'sale' license: {license}") # "LGPL-3" # Filter dependencies to exclude core addons manifest_depends = ['base', 'sale', 'my_partner_addon', 'stock'] external_depends = [dep for dep in manifest_depends if not is_core_addon(dep, series)] print(f"External dependencies: {external_depends}") # ['my_partner_addon'] ``` -------------------------------- ### Generate Python Package Metadata from Odoo Addon (Python) Source: https://context7.com/acsone/manifestoo-core/llms.txt Converts an Odoo addon directory into Python Package Metadata 2.1 format, suitable for packaging and PyPI distribution. It supports various options for overriding detected information like Odoo series, dependencies, and Python requirements. ```Python from pathlib import Path from manifestoo_core.metadata import ( metadata_from_addon_dir, MetadataOptions, addon_name_to_distribution_name, addon_name_to_requirement, distribution_name_to_addon_name, POST_VERSION_STRATEGY_DOT_N, POST_VERSION_STRATEGY_NONE, ) from manifestoo_core.odoo_series import OdooSeries addon_dir = Path("/path/to/my_addon") # Generate basic metadata metadata = metadata_from_addon_dir(addon_dir) print(f"Name: {metadata['Name']}") # e.g., "odoo-addon-my_addon" print(f"Version: {metadata['Version']}") # e.g., "16.0.1.0.0" print(f"Summary: {metadata['Summary']}") print(f"Author: {metadata['Author']}") print(f"License: {metadata['License']}") print(f"Requires-Python: {metadata['Requires-Python']}") # Get all Requires-Dist entries requires = metadata.get_all('Requires-Dist') or [] print(f"Dependencies: {requires}") # Get long description (README content) long_description = metadata.get_payload() print(f"Description type: {metadata['Description-Content-Type']}") # Generate with options options: MetadataOptions = { # Override detected Odoo series 'odoo_series_override': '16.0', # Override specific addon dependencies 'depends_override': { 'partner_autocomplete': 'odoo-addon-partner_autocomplete>=16.0dev,<16.1dev', 'some_addon': '', # Empty string to exclude dependency }, # Override external Python dependencies 'external_dependencies_override': { 'python': { 'ldap': 'python-ldap>=3.0', 'custom_lib': ['lib1>=1.0', 'lib2>=2.0'], # Multiple packages } }, # Only include external (non-Odoo) dependencies 'external_dependencies_only': True, # Override post-version strategy 'post_version_strategy_override': POST_VERSION_STRATEGY_NONE, } metadata = metadata_from_addon_dir(addon_dir, options=options) # Convert between addon names and distribution names series = OdooSeries.v16_0 dist_name = addon_name_to_distribution_name('my_addon', series) print(f"Distribution name: {dist_name}") # "odoo-addon-my_addon" # Get requirement specifier with version constraints requirement = addon_name_to_requirement('my_addon', series) print(f"Requirement: {requirement}") # "odoo-addon-my_addon>=16.0dev,<16.1dev" # Reverse: distribution name to addon name addon_name = distribution_name_to_addon_name('odoo-addon-my_addon') print(f"Addon name: {addon_name}") # "my_addon" ``` -------------------------------- ### Detect Odoo Series and Editions from Version String (Python) Source: https://context7.com/acsone/manifestoo-core/llms.txt Parses an Odoo addon version string to detect the Odoo series and edition. It requires the version string to have at least five parts. Supported Odoo series can also be listed. ```Python from manifestoo_core.odoo_series import OdooSeries, OdooEdition, detect_from_addon_version # Version format: .0... version = "16.0.1.2.3" detected_series = detect_from_addon_version(version) if detected_series: print(f"Detected: {detected_series.value}") # "16.0" else: print("Could not detect series (needs at least 5 version parts)") # OdooEdition for CE/EE distinction ce_edition = OdooEdition.CE # value: "c" ee_edition = OdooEdition.EE # value: "e" # List all supported series for series in OdooSeries: print(f"Supported: Odoo {series.value}") ``` -------------------------------- ### OdooSeries and OdooEdition - Version Detection Source: https://context7.com/acsone/manifestoo-core/llms.txt The `OdooSeries` enum and `OdooEdition` class are used for version detection and handling Odoo Community (CE) and Enterprise (EE) editions. They support Odoo versions from 8.0 to 19.0 and provide methods to parse series from strings and detect series from addon versions or sets of addons. ```python from manifestoo_core.odoo_series import ( OdooSeries, OdooEdition, detect_from_addon_version, detect_from_addons_set ) from manifestoo_core.exceptions import UnsupportedOdooSeries # Use OdooSeries enum directly series = OdooSeries.v16_0 print(f"Series value: {series.value}") # "16.0" # Parse series from string try: series = OdooSeries.from_str("17.0") print(f"Parsed series: {series}") # OdooSeries.v17_0 except UnsupportedOdooSeries: print("Unsupported Odoo version") # Detect series from addon version string ``` -------------------------------- ### Automatic Version Increments with Git Post-Versioning (Python) Source: https://context7.com/acsone/manifestoo-core/llms.txt This functionality enables automatic version increments based on git commits since the last version change. It supports different strategies tailored to Odoo series, such as `.99.devN`, `+1.devN`, and `.N`. Dependencies include `manifestoo_core.addon` and `manifestoo_core.git_postversion`. ```python from pathlib import Path from manifestoo_core.addon import Addon from manifestoo_core.git_postversion import ( get_git_postversion, POST_VERSION_STRATEGY_NONE, POST_VERSION_STRATEGY_NINETYNINE_DEVN, POST_VERSION_STRATEGY_P1_DEVN, POST_VERSION_STRATEGY_DOT_N, ) addon = Addon.from_addon_dir(Path("/path/to/my_addon")) # Strategy: none - return manifest version as-is version = get_git_postversion(addon, POST_VERSION_STRATEGY_NONE) print(f"No post-version: {version}") # "16.0.1.0.0" # Strategy: .99.devN (Odoo 8-12) # If 3 commits since version change: "16.0.1.0.0.99.dev3" version = get_git_postversion(addon, POST_VERSION_STRATEGY_NINETYNINE_DEVN) # Strategy: +1.devN (Odoo 13-14) # If 3 commits since version change: "16.0.1.0.1.dev3" version = get_git_postversion(addon, POST_VERSION_STRATEGY_P1_DEVN) # Strategy: .N (Odoo 15+, default) # If 3 commits since version change: "16.0.1.0.0.3" version = get_git_postversion(addon, POST_VERSION_STRATEGY_DOT_N) print(f"Post-versioned: {version}") # Note: metadata_from_addon_dir automatically applies the appropriate # strategy based on the detected Odoo series, unless overridden ``` -------------------------------- ### Detect Odoo Series from Addon Version Source: https://github.com/acsone/manifestoo-core/blob/main/docs/api.md Detects the Odoo series based on a given addon version string. ```APIDOC ## GET /detect_odoo_series ### Description Detects the Odoo Series from an addon version string. Returns `None` if the version is not recognized. ### Method GET ### Endpoint `/detect_odoo_series` ### Parameters #### Query Parameters - **version** (str) - Required - The addon version string to detect the Odoo series from. ### Response #### Success Response (200) - **OdooSeries** (enum) | None - The detected Odoo series (CE or EE) or None if not recognized. #### Response Example ```json { "odoo_series": "ce" } ``` #### Error Response (400) - **error** (str) - Description of the error if the version is invalid or not recognized. ``` -------------------------------- ### Manifest Class - Parse Odoo Manifest Files Source: https://context7.com/acsone/manifestoo-core/llms.txt The `Manifest` class parses Odoo addon manifest files, providing typed access to manifest fields. It supports loading manifests from files, strings, or dictionaries, and includes validation for manifest structure. It allows access to various manifest properties like name, version, dependencies, and external dependencies. ```python from pathlib import Path from manifestoo_core.manifest import Manifest, get_manifest_path, InvalidManifest # Find and parse manifest from addon directory addon_dir = Path("/path/to/my_addon") manifest_path = get_manifest_path(addon_dir) # Returns Path or None if manifest_path: manifest = Manifest.from_file(manifest_path) # Access manifest properties print(f"Name: {manifest.name}") print(f"Summary: {manifest.summary}") print(f"Version: {manifest.version}") print(f"License: {manifest.license}") print(f"Author: {manifest.author}") print(f"Authors list: {manifest.authors}" ) # Tuple of author names print(f"Category: {manifest.category}") print(f"Website: {manifest.website}") print(f"Installable: {manifest.installable}") print(f"Dependencies: {manifest.depends}") print(f"External deps: {manifest.external_dependencies}") print(f"Development status: {manifest.development_status}") # Parse manifest from string manifest_str = """ { 'name': 'My Addon', 'version': '16.0.1.0.0', 'depends': ['base', 'sale'], 'author': 'ACME Corp, Partner Inc', 'license': 'LGPL-3', 'external_dependencies': { 'python': ['requests', 'pandas'], }, } """ try: manifest = Manifest.from_str(manifest_str) print(f"Parsed: {manifest.name} v{manifest.version}") except InvalidManifest as e: print(f"Invalid manifest: {e}") # Parse from dictionary manifest_dict = { 'name': 'Test Addon', 'version': '17.0.1.0.0', 'depends': ['base'], } manifest = Manifest.from_dict(manifest_dict) ``` -------------------------------- ### Addon Class - Load and Validate Odoo Addons Source: https://context7.com/acsone/manifestoo-core/llms.txt The `Addon` class in manifestoo-core represents an Odoo addon. It can validate addon directory structures, load manifests, and extract addon information like name, version, and dependencies. It handles potential exceptions such as `AddonNotFound` and `AddonNotFoundNoManifest` and supports loading non-installable addons. ```python from pathlib import Path from manifestoo_core.addon import Addon, is_addon_dir from manifestoo_core.exceptions import AddonNotFound, AddonNotFoundNoManifest # Check if a directory is a valid addon addon_path = Path("/path/to/my_addon") if is_addon_dir(addon_path): print(f"{addon_path.name} is a valid Odoo addon") # Load an addon from directory try: addon = Addon.from_addon_dir(addon_path) print(f"Addon name: {addon.name}") print(f"Manifest path: {addon.manifest_path}") print(f"Version: {addon.manifest.version}") print(f"Dependencies: {addon.manifest.depends}") except AddonNotFoundNoManifest: print("No manifest file found") except AddonNotFound as e: print(f"Invalid addon: {e}") # Allow non-installable addons (installable=False in manifest) addon = Addon.from_addon_dir(addon_path, allow_not_installable=True) ``` -------------------------------- ### Manifest Class Source: https://github.com/acsone/manifestoo-core/blob/main/docs/api.md The Manifest class represents an Odoo manifest file, allowing parsing from various sources and access to manifest fields. ```APIDOC ## Class: manifestoo_core.manifest.Manifest ### Description Represents an Odoo manifest file. ### Methods #### classmethod from_dict(manifest_dict, source='') Parse a manifest dictionary into a [`Manifest`](#manifestoo_core.manifest.Manifest) object. Raises [`InvalidManifest`](#manifestoo_core.manifest.InvalidManifest) if the manifest is invalid. **Parameters:** - **manifest_dict** (*Dict[str, Any]*) - The dictionary representing the manifest. - **source** (*str*) - The source of the manifest dictionary (e.g., filename). **Returns:** - [*Manifest*](#manifestoo_core.manifest.Manifest) - A Manifest object. #### classmethod from_str(manifest_str, source='') Parse a manifest string into a [`Manifest`](#manifestoo_core.manifest.Manifest) object. Raises [`InvalidManifest`](#manifestoo_core.manifest.InvalidManifest) if the manifest is invalid. **Parameters:** - **manifest_str** (*str*) - The string representing the manifest. - **source** (*str*) - The source of the manifest string. **Returns:** - [*Manifest*](#manifestoo_core.manifest.Manifest) - A Manifest object. #### classmethod from_file(manifest_path) Parse a manifest file into a [`Manifest`](#manifestoo_core.manifest.Manifest) object. Raises [`InvalidManifest`](#manifestoo_core.manifest.InvalidManifest) if the manifest is invalid. **Parameters:** - **manifest_path** (*Path*) - The path to the manifest file. **Returns:** - [*Manifest*](#manifestoo_core.manifest.Manifest) - A Manifest object. ### Properties - **name** (*str* | None) - The name field. - **summary** (*str* | None) - The value of the summary field. - **description** (*str* | None) - The value of the description field. - **version** (*str* | None) - The value of the version field. - **installable** (*bool*) - The value of the installable field if set, else True. - **depends** (*List[str]*) - The value of the depends field if set, else []. - **external_dependencies** (*Dict[str, Any]*) - The value of the external_dependencies field if set, else {}. - **license** (*str* | None) - The value of the license field. - **author** (*str* | None) - The value of the author field. - **authors** (*Tuple[str, ...]* | None) - The value of the author field as a list of authors. - **category** (*str* | None) - The value of the category field. - **website** (*str* | None) - The value of the website field. - **development_status** (*str* | None) - The value of the development_status field. ``` -------------------------------- ### Odoo Edition Enum Source: https://github.com/acsone/manifestoo-core/blob/main/docs/api.md Defines the possible editions for Odoo. ```APIDOC ## Enum: OdooEdition ### Description Represents an Odoo Edition. ### Members - **CE** ('c') - Community Edition - **EE** ('e') - Enterprise Edition ### Initialization `__new__(value)`: Initializes a new OdooEdition instance. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.