Last active
January 24, 2021 23:49
-
-
Save 4wrxb/64c1a5e852bb2a88a06a00b3b659640a to your computer and use it in GitHub Desktop.
Python 3 script to convert presets from a Prusa Config bundle into CSV for side-by-side comparison
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# Convert a PrusaSlicer_config_bundle.ini file to a set of CSVs where options can be compared across presets | |
# Author: Will O (https://github.com/4wrxb) | |
# Email: [email protected] | |
# Date: 2021-01-24 | |
# Copyright (C) 2021 Will O | |
# | |
# This program is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation, either version 3 of the License, or | |
# (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
import sys | |
import csv | |
from configparser import ConfigParser | |
######################################################################################################################## | |
# CONFIGURATION # | |
######################################################################################################################## | |
# General | |
#-------- | |
# CONTROL DEBUG OUTPUT | |
enable_debug = 0 | |
# Bypass warnings on the "preset" section (this is just active state) | |
supress_presets_warning = 1 | |
# Disable outputting a CSV for a given type if it only has one preset | |
suppress_single_entry_csv = 1 | |
# Supported Preset (section) Types | |
#--------------------------------- | |
# Each preset in Prusa maps to a section. Each configured types will be parsed in a seperate .csv file. | |
# Seciton name should be "<type>:*" in the .ini to be recognized otherwise script below will need edited | |
section_types = ["print", "filament", "printer"] | |
# WARNING: this is not checked, make sure entries are unique etc. or there will be unexpected behavior | |
######################################################################################################################## | |
# END CONFIGURATION # | |
######################################################################################################################## | |
# My logging functions | |
def fail(message, retcode=1): | |
print("FATAL : " + message) | |
exit(retcode) | |
def error(message): | |
print("ERROR : " + message) | |
def warn(message): | |
print("WARNING : " + message) | |
def debug(message): | |
if enable_debug == 1: | |
print("DEBUG : " + message) | |
def info(message): | |
print("INFO : " + message) | |
# Read in the INI | |
with open(sys.argv[1], "r") as ini_f: | |
# Disable interpolation, % are used as raw values by PrusaSlicer | |
ini = ConfigParser(interpolation=None) | |
ini.read_file(ini_f) | |
# Categorize each section, collect row names and options | |
#------------------------------------------------------- | |
# Collect the columns and rows in each CSV (section type) | |
# These will be two dictionaries of sets where the key is the section type | |
# The entries will be a dictionary of dictionaries (section then option) that need translated on output | |
# Columns (fields to the DictWriter function) translate to the section in the ini | |
sec_lists = {x: set() for x in section_types} | |
# Options within each section translate to a row in the CSV (we take a superset) | |
opt_lists = {x: set() for x in section_types} | |
# Option entries themselves will need transposed laters | |
entries = {} | |
for sec in ini.sections(): | |
for sectype in section_types: | |
if sec.startswith(sectype + ":"): | |
sec_lists[sectype].add(sec) | |
for key,value in ini.items(sec): | |
opt_lists[sectype].add(key) | |
continue | |
if sec in set.union(*sec_lists.values()): | |
# If the section was recognized than store all options | |
entries[sec] = {} | |
for key,value in ini.items(sec): | |
entries[sec][key] = value | |
elif supress_presets_warning == 1 and sec == "presets": | |
debug("Not warning that " + sec + " is unrecognized due to supression option.") | |
continue | |
else: | |
# If the section wasn't recognized print a warning | |
warn("Dropping section " + sec + " because its type is not supported.") | |
# Output a CSV file for each section type | |
#---------------------------------------- | |
for sectype in section_types: | |
# Make sure there was a matching section of this type | |
# Note that the sectype key is defined on initialization, but the value (set) may be empty | |
if not sec_lists[sectype]: | |
debug("No sections matched type " + sectype + " a csv for this type will not be written.") | |
continue | |
if len(sec_lists[sectype]) == 1: | |
debug("Not writing single-column csv for " + sectype + " due to supression option.") | |
continue | |
# Prepare the section and option lists for the sectype | |
sections = sorted(sec_lists[sectype]) | |
options = sorted(opt_lists[sectype]) | |
# Name the csv file as orig.ini_[sectype].csv, and create it | |
# FIXME: this will blindly overwrite files (and could leave stale ones for sections that aren't written) | |
# will be better to check for argv[1]*.csv and fail early | |
with open(sys.argv[1] + "_" + sectype + ".csv", "w", newline='') as out_f: | |
# The fields are (alphebatized) sections with the option name first | |
out_csv = csv.DictWriter(out_f, fieldnames=["option"] + sections) | |
out_csv.writeheader() | |
# Assemble a row for each option and assemble it across sections | |
for opt in options: | |
# No need to initialize the row dictionary, DictWriter inserts blank entries automatically | |
row = {} | |
# Label the row | |
row["option"] = opt | |
# Get the option for each section (if it exists) and put it in the row | |
for sec in sections: | |
if opt in entries[sec]: | |
row[sec] = entries[sec][opt] | |
out_csv.writerow(row) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment