from __future__ import annotations import os import re from configparser import ConfigParser, MissingSectionHeaderError from typing import Any def generate_conf(profiles: dict[str, Any], id: str) -> dict[str, str]: """Recursively merges inherited profiles into a single configuration dictionary.""" if not (profile := profiles.get(id)): return {} if not profile.conf_dict: return {} conf_current = profiles[id].conf_dict.copy() if conf_current.get('inherits', False): curr_category = id.split(":")[0] # Split on semicolon for multiple inheritance inherited_ids = [ curr_category + ":" + inherit_id.strip() for inherit_id in conf_current['inherits'].split(';') ] merged_conf = {} for inherit_id in inherited_ids: if inherit_id in profiles: inherited_conf = generate_conf(profiles, inherit_id) merged_conf.update(inherited_conf) merged_conf.update(conf_current) conf_current = merged_conf conf_current.pop('inherits', None) conf_current.pop('renamed_from', None) return conf_current def ini_to_dict(path: str) -> tuple[bool, dict[str, dict[str, str]]]: """Parses a PrusaSlicer INI file into a dictionary of sections.""" with open(path, 'r') as file: content = file.read() config = ConfigParser(interpolation=None) try: config.read_string(content) has_header = True except MissingSectionHeaderError: # Determine category based on specific IDs in the content if re.search(r'^filament_settings_id', content, re.MULTILINE): cat = 'filament' elif re.search(r'^print_settings_id', content, re.MULTILINE): cat = 'print' elif re.search(r'^printer_settings_id', content, re.MULTILINE): cat = 'printer' else: raise ValueError(f"Unable to determine category for the INI file: {path}") name = os.path.splitext(os.path.basename(path))[0] default_section = f"[{cat}:{name}]\n" + content config.read_string(default_section) has_header = False return has_header, { section: dict(sorted(config.items(section))) for section in sorted(config.sections()) } def ini_content_to_dict(path: str) -> dict[str, str]: """Parses a PrusaSlicer INI file without sections into a flat dictionary.""" with open(path, 'r') as file: content = file.read() config = ConfigParser(interpolation=None) default_section = f"[default:default]\n" + content config.read_string(default_section) return dict(sorted(config.items(config.sections()[0])))