# SPDX-License-Identifier: MIT OR GPL-3.0-or-later import re from dataclasses import dataclass from pathlib import Path from typing import Optional @dataclass(frozen=True) class BlenderManifest: id: str version: tuple[int, int, int] blender_version_min: tuple[int, int, int] blender_version_max: Optional[tuple[int, int, int]] @classmethod def default_blender_manifest_path(cls) -> Path: return Path(__file__).parent.parent / "blender_manifest.toml" @classmethod def read_str(cls, blender_manifest: str, key: str) -> Optional[str]: # When the version of Python used by the minimum supported version of Blender # exceeds 3.11, it is rewritten in the tomli library. lines = list(map(str.strip, blender_manifest.splitlines())) pattern = key + r' = "([^"]+)"' for line in lines: match = re.fullmatch(pattern, line) if not match: continue return match[1] return None @classmethod def read_3_tuple_version( cls, blender_manifest: str, key: str ) -> Optional[tuple[int, int, int]]: # When the version of Python used by the minimum supported version of Blender # exceeds 3.11, it is rewritten in the tomli library. lines = list(map(str.strip, blender_manifest.splitlines())) pattern = key + r' = "(\d+)\.(\d+)\.(\d+)"' for line in lines: match = re.fullmatch(pattern, line) if not match: continue return (int(match[1]), int(match[2]), int(match[3])) return None @classmethod def read(cls, blender_manifest: Optional[str] = None) -> "BlenderManifest": if blender_manifest is None: blender_manifest = cls.default_blender_manifest_path().read_text( encoding="UTF-8" ) addon_id = cls.read_str(blender_manifest, "id") if addon_id is None: message = "'id' was not found in blender manifest" raise ValueError(message) version = cls.read_3_tuple_version(blender_manifest, "version") if version is None: message = "'version' was not found in blender manifest" raise ValueError(message) blender_version_min = cls.read_3_tuple_version( blender_manifest, "blender_version_min" ) if blender_version_min is None: message = "'blender_version_min' was not found in blender manifest" raise ValueError(message) return BlenderManifest( id=addon_id, version=version, blender_version_min=blender_version_min, blender_version_max=cls.read_3_tuple_version( blender_manifest, "blender_version_max" ), )