75 lines
2.7 KiB
Python
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])))
|