Source code for bridge.pipelines.utils.conversions

"""
Utility functions for converting object types and preparing them for serialization.

This module provides small, focused helpers that are useful when generating
artifacts such as YAML, JSON, or Markdown documents from richer Python objects.
"""

import base64
import re
from enum import Enum
from pathlib import Path
from typing import Any, TypeVar

from pydantic import BaseModel

E = TypeVar("E", bound=Enum)


[docs] def find_matching_enum_member[E: Enum]( value: str, enum_cls: type[E], ) -> E | None: """ Resolve a free-text string to a member of a given Enum via case-insensitive matching on both member `.value` and `.name`. The input is matched against: 1. `str(member.value)` (primary match target) 2. `member.name` (fallback match target) Matching is performed in a case-insensitive manner. No fuzzy matching, partial matching, or alias expansion is applied. Parameters ---------- value : str Free-text input to be normalized. enum_cls : type[E] The Enum class to match against. Returns ------- E | None The matching Enum member if an exact case-insensitive match is found against either `.value` or `.name`; otherwise ``None``. Notes ----- - This function assumes Enum values are string-like or safely castable to `str`. - If multiple Enum members share the same normalized value, the first match in definition order is returned. """ value_lower = value.lower() for member in enum_cls: if str(member.value).lower() == value_lower or member.name.lower() == value_lower: return member return None
[docs] def svg_to_base64(svg_path: str) -> str: """ Convert an SVG file into a cleaned, base64-encoded string. This helper is intended for scenarios where an SVG needs to be embedded directly into another format (e.g. HTML `img` tags with data URIs, Markdown, or JSON/YAML configuration files) rather than referenced by filesystem path. Parameters ---------- svg_path : str Path to the SVG file on disk. Returns ------- str A base64-encoded string representing the cleaned SVG content. The resulting string contains only ASCII characters and no newlines, and can be safely used in data URIs such as:: f"data:image/svg+xml;base64,{svg_to_base64('icon.svg')}" Raises ------ FileNotFoundError If the SVG file does not exist at the given path. """ svg_path = Path(svg_path) if not svg_path.exists(): raise FileNotFoundError(f"SVG file not found: {svg_path}") text = svg_path.read_text(encoding="utf-8") # remove XML declaration if present text = re.sub(r"^<\?xml[^>]*\?>\s*", "", text, flags=re.IGNORECASE) # strip comments text = re.sub(r"<!--.*?-->", "", text, flags=re.DOTALL) # collapse trivial whitespace between tags text = re.sub(r">\s+<", "><", text).strip() encoded_svg = base64.b64encode(text.encode("utf-8")).decode("ascii").replace("\n", "") return encoded_svg
[docs] def object_to_primitive(obj: Any) -> Any: """ Recursively convert complex objects into plain Python types. This function walks an arbitrary Python object and produces a structure composed only of "primitive" container-friendly types: - ``dict`` with primitive values - ``list`` of primitive values - ``str``, ``int``, ``float``, ``bool``, or ``None`` It is useful before serializing data to JSON, YAML, or other text-based formats where custom classes (e.g. Pydantic models, enums) would otherwise introduce unwanted artifacts or non-serializable types. Conversion rules ---------------- - **Pydantic models**: - For v2 models, ``model_dump(mode="python", exclude_none=True)`` is used. - For v1 models, ``dict(exclude_none=True)`` is used. - The resulting dict is then processed recursively. - **Enum instances**: - Replaced with their ``.value``. - **Mappings / dicts**: - Keys are left as-is, values are passed through ``object_to_primitive`` recursively. - **Iterables (list, tuple, set)**: - Converted to a ``list`` with each element converted recursively. - **Anything else**: - Returned unchanged, under the assumption that it is already a primitive type or is otherwise safely serializable. Parameters ---------- obj : Any The object (or nested structure of objects) to convert. Returns ------- Any A recursively converted object that only contains primitive types and containers thereof. """ # Pydantic models if isinstance(obj, BaseModel): if hasattr(obj, "model_dump"): data = obj.model_dump(mode="python", exclude_none=True) else: data = obj.dict(exclude_none=True) return object_to_primitive(data) # enums if isinstance(obj, Enum): return obj.value # dicts if isinstance(obj, dict): return {k: object_to_primitive(v) for k, v in obj.items()} # lists / tuples / sets if isinstance(obj, (list, tuple, set)): return [object_to_primitive(v) for v in obj] # everything else is assumed to already be primitive or stringify-able return obj