nodeslicer/infra/prusaslicer_profiles/utils.py

75 lines
2.7 KiB
Python

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])))