Source code for r2x_core.utils.export

"""Component record export and CSV serialization."""

from __future__ import annotations

import csv
from collections.abc import Callable
from pathlib import Path
from typing import Any

from infrasys import Component
from loguru import logger


[docs] def components_to_records( system: Any, *, filter_func: Callable[[Component], bool] | None = None, fields: list[str] | None = None, key_mapping: dict[str, str] | None = None, ) -> list[dict[str, Any]]: """Convert system components to a list of dictionaries (records). Parameters ---------- system : System The system to extract components from. filter_func : Callable, optional Function to filter components. Should accept a component and return bool. fields : list, optional List of field names to include. If None, includes all fields. key_mapping : dict, optional Dictionary mapping component field names to record keys. Returns ------- list[dict[str, Any]] List of component records as dictionaries. """ # Use a generator to avoid holding all component dicts in memory # simultaneously. The result is still a list (public API contract), # but the generator prevents holding both the component objects AND # the serialized dicts in memory at the same time. def _iter_records(): """Yield one record dict at a time with filtering and key mapping applied.""" for component in system.get_components(Component, filter_func=filter_func): record = component.model_dump() if fields is not None: record = {k: v for k, v in record.items() if k in fields} if key_mapping is not None: record = {key_mapping.get(k, k): v for k, v in record.items()} yield record return list(_iter_records())
[docs] def export_components_to_csv( system: Any, *, file_path: Path | str, filter_func: Callable[[Component], bool] | None = None, fields: list[str] | None = None, key_mapping: dict[str, str] | None = None, **dict_writer_kwargs: Any, ) -> None: """Export all components or filtered components to a CSV file. Parameters ---------- system : System The system to export components from. file_path : Path | str Output CSV file path. filter_func : Callable, optional Function to filter components by. Exports all if None. fields : list, optional List of field names to include. Exports all if None. key_mapping : dict, optional Mapping of component field names to CSV column names. **dict_writer_kwargs Additional arguments passed to csv.DictWriter. """ records = components_to_records(system, filter_func=filter_func, fields=fields, key_mapping=key_mapping) if not records: logger.warning("No components to export") return fpath = Path(file_path) fpath.parent.mkdir(parents=True, exist_ok=True) fieldnames = list(records[0].keys()) with open(fpath, "w", newline="") as f: writer = csv.DictWriter(f, fieldnames=fieldnames, extrasaction="ignore", **dict_writer_kwargs) writer.writeheader() writer.writerows(records) logger.info("Exported {} components to {}", len(records), fpath)