mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-06 07:11:10 +00:00
Load a CLI Project's Printer and Process Settings as the GUI Does
The CLI filled only the keys a project lacked from its system preset. The GUI builds a project preset differently: the project's values go over the default preset, without the print-host keys, and every key the project does not list in different_settings_to_system is refreshed to its base system preset's current value. After a profile update the two sliced the same project differently. That step now lives in Preset::load_external_config, which takes plain configs and gets the base preset from a callback, so the collection lookup stays in PresetCollection. PresetBundle::project_different_keys builds the kept-key set from a project's escaped entry, adding the preset bookkeeping keys, and is used by both the GUI and the CLI. PresetCollection::load_external_preset calls the shared step with no change in behaviour. The CLI now builds the project's printer and process configs with the same step, passing the system preset from resolve_system_preset. That drops the hand-kept skip list for print-host and variant-layout keys and the legacy-key check: the shared step already excludes print-host keys and maps per-variant values onto the base preset's variant layout. The --uptodate path and a printer or process given on the command line are left as they were. Because the GUI's kept-key set always holds the bookkeeping keys, the refresh runs for every project that names a system preset, so the CLI now loads that preset's vendor on every such run.
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
# End-to-end check that the CLI fills settings missing from a project from the project's system presets.
|
||||
# End-to-end check that the CLI loads a project's printer and process settings as the GUI does.
|
||||
#
|
||||
# A project saved before an option existed has no value for it. The GUI takes such keys from the
|
||||
# project's system printer and process presets, not from the option defaults, and the CLI must slice
|
||||
# the project with the same values. A project is exported from the shipped Bambu Lab P1S presets, one
|
||||
# printer key and one process key are removed from it, one kept key is changed, and it is sliced again.
|
||||
# The GUI takes every key a project does not list as changed from the project's current system preset:
|
||||
# keys saved before an option existed, and keys holding an older system value. Keys the project lists
|
||||
# in different_settings_to_system keep the project's value. A project is exported from the shipped
|
||||
# Bambu Lab P1S presets; one printer key and one process key are removed, one printer key and one
|
||||
# process key are changed without being listed, one key is changed and listed, and it is sliced again.
|
||||
#
|
||||
# usage: test_cli_project_missing_keys.sh <orca-slicer binary> <python3> <resources/profiles/BBL>
|
||||
set -u
|
||||
@@ -46,7 +47,8 @@ slice base "$WORK/cube.stl" \
|
||||
--load-settings "$PROFILES/machine/Bambu Lab P1S 0.4 nozzle.json;$PROFILES/process/0.20mm Standard @BBL X1C.json" \
|
||||
--load-filaments "$PROFILES/filament/Bambu PLA Basic @BBL P1S 0.4 nozzle.json"
|
||||
|
||||
# The removed keys, with their option defaults from PrintConfig.cpp, and a kept key with a new value.
|
||||
# The removed keys, with their option defaults from PrintConfig.cpp; stale keys changed without being
|
||||
# listed as different, which must come back with the system value; and a listed key the project keeps.
|
||||
"$PY" - "$WORK/base/out.3mf" "$WORK/old.3mf" <<'EOF' || exit $?
|
||||
import json, sys, zipfile
|
||||
|
||||
@@ -62,8 +64,13 @@ with zipfile.ZipFile(src) as zin, zipfile.ZipFile(dst, "w", zipfile.ZIP_DEFLATED
|
||||
print("SKIP: %s is %s in the system preset, the option default, so the test cannot tell them apart" % (key, default))
|
||||
sys.exit(77)
|
||||
expected = {key: config.pop(key) for key in missing}
|
||||
for key in ("top_shell_layers", "extruder_clearance_height_to_rod"):
|
||||
expected[key] = config[key]
|
||||
config[key] = str(int(float(config[key])) + 1)
|
||||
expected["wall_loops"] = str(int(config["wall_loops"]) + 1)
|
||||
config["wall_loops"] = expected["wall_loops"]
|
||||
different = config["different_settings_to_system"]
|
||||
different[0] = ";".join([k for k in different[0].split(";") if k] + ["wall_loops"])
|
||||
data = json.dumps(config, indent=4)
|
||||
zout.writestr(item, data)
|
||||
with open(dst + ".expected.json", "w") as f:
|
||||
|
||||
@@ -5785,3 +5785,158 @@ TEST_CASE("A system preset no vendor lists is not resolved", "[Preset][Bundle]")
|
||||
ForwardCompatibilitySubstitutionRule::EnableSilent, error));
|
||||
CHECK_FALSE(error.empty());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// A default preset config for type, built the way PresetBundle builds its default presets.
|
||||
DynamicPrintConfig external_default_config(Preset::Type type)
|
||||
{
|
||||
DynamicPrintConfig config;
|
||||
config.apply_only(static_cast<const PrintRegionConfig &>(FullPrintConfig::defaults()),
|
||||
type == Preset::TYPE_PRINTER ? Preset::printer_options() : Preset::print_options());
|
||||
Preset::inherits(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
// A find_base callback that counts its calls and returns base.
|
||||
auto base_finder(DynamicPrintConfig *base, int &calls)
|
||||
{
|
||||
return [base, &calls](const std::string &) {
|
||||
++calls;
|
||||
return base;
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("A key missing from a project takes the default preset value when there is no base", "[Preset][ExternalPreset]")
|
||||
{
|
||||
DynamicPrintConfig defaults = external_default_config(Preset::TYPE_PRINT);
|
||||
defaults.set("wall_loops", 7, true);
|
||||
const DynamicPrintConfig project;
|
||||
int calls = 0;
|
||||
|
||||
const DynamicPrintConfig config = Preset::load_external_config(Preset::TYPE_PRINT, defaults, project, {"sparse_infill_density"},
|
||||
base_finder(nullptr, calls));
|
||||
CHECK(calls == 1);
|
||||
CHECK(config.opt_int("wall_loops") == 7);
|
||||
}
|
||||
|
||||
TEST_CASE("A key missing from a project takes its base preset value", "[Preset][ExternalPreset]")
|
||||
{
|
||||
DynamicPrintConfig defaults = external_default_config(Preset::TYPE_PRINT);
|
||||
defaults.set("wall_loops", 7, true);
|
||||
DynamicPrintConfig base = defaults;
|
||||
base.set("wall_loops", 5, true);
|
||||
const DynamicPrintConfig project;
|
||||
int calls = 0;
|
||||
|
||||
const DynamicPrintConfig config = Preset::load_external_config(Preset::TYPE_PRINT, defaults, project, {"sparse_infill_density"},
|
||||
base_finder(&base, calls));
|
||||
CHECK(config.opt_int("wall_loops") == 5);
|
||||
}
|
||||
|
||||
TEST_CASE("A project key listed as different keeps the project value", "[Preset][ExternalPreset]")
|
||||
{
|
||||
const DynamicPrintConfig defaults = external_default_config(Preset::TYPE_PRINT);
|
||||
DynamicPrintConfig base = defaults;
|
||||
base.set("wall_loops", 5, true);
|
||||
DynamicPrintConfig project;
|
||||
project.set("wall_loops", 4, true);
|
||||
int calls = 0;
|
||||
|
||||
const DynamicPrintConfig config = Preset::load_external_config(Preset::TYPE_PRINT, defaults, project, {"wall_loops"},
|
||||
base_finder(&base, calls));
|
||||
CHECK(config.opt_int("wall_loops") == 4);
|
||||
}
|
||||
|
||||
TEST_CASE("A project key not listed as different is refreshed to the base value", "[Preset][ExternalPreset]")
|
||||
{
|
||||
const DynamicPrintConfig defaults = external_default_config(Preset::TYPE_PRINT);
|
||||
DynamicPrintConfig base = defaults;
|
||||
base.set("wall_loops", 5, true);
|
||||
DynamicPrintConfig project;
|
||||
project.set("wall_loops", 4, true);
|
||||
project.set("inherits", "Base Process", true);
|
||||
std::string inherits;
|
||||
|
||||
const DynamicPrintConfig config = Preset::load_external_config(Preset::TYPE_PRINT, defaults, project, {"sparse_infill_density"},
|
||||
[&base, &inherits](const std::string &name) {
|
||||
inherits = name;
|
||||
return &base;
|
||||
});
|
||||
CHECK(inherits == "Base Process");
|
||||
CHECK(config.opt_int("wall_loops") == 5);
|
||||
}
|
||||
|
||||
TEST_CASE("An empty different settings list keeps the project values without a base", "[Preset][ExternalPreset]")
|
||||
{
|
||||
DynamicPrintConfig defaults = external_default_config(Preset::TYPE_PRINT);
|
||||
defaults.set("top_shell_layers", 7, true);
|
||||
DynamicPrintConfig base = defaults;
|
||||
base.set("wall_loops", 5, true);
|
||||
base.set("top_shell_layers", 9, true);
|
||||
DynamicPrintConfig project;
|
||||
project.set("wall_loops", 4, true);
|
||||
int calls = 0;
|
||||
|
||||
const DynamicPrintConfig config = Preset::load_external_config(Preset::TYPE_PRINT, defaults, project, {}, base_finder(&base, calls));
|
||||
CHECK(calls == 0);
|
||||
CHECK(config.opt_int("wall_loops") == 4);
|
||||
CHECK(config.opt_int("top_shell_layers") == 7);
|
||||
}
|
||||
|
||||
TEST_CASE("Print-host keys are never taken from a project", "[Preset][ExternalPreset]")
|
||||
{
|
||||
DynamicPrintConfig defaults = external_default_config(Preset::TYPE_PRINTER);
|
||||
defaults.set("print_host", "", true);
|
||||
defaults.set("printhost_apikey", "", true);
|
||||
DynamicPrintConfig project;
|
||||
project.set("print_host", "http://project-host", true);
|
||||
project.set("printhost_apikey", "project-key", true);
|
||||
project.set("printer_notes", "project notes", true);
|
||||
t_config_option_keys keys;
|
||||
int calls = 0;
|
||||
|
||||
const DynamicPrintConfig config = Preset::load_external_config(Preset::TYPE_PRINTER, defaults, project, {"printer_notes"},
|
||||
base_finder(nullptr, calls), &keys);
|
||||
CHECK(config.opt_string("print_host").empty());
|
||||
CHECK(config.opt_string("printhost_apikey").empty());
|
||||
CHECK(config.opt_string("printer_notes") == "project notes");
|
||||
CHECK_FALSE(contains_key(keys, "print_host"));
|
||||
CHECK_FALSE(contains_key(keys, "printhost_apikey"));
|
||||
CHECK(contains_key(keys, "printer_notes"));
|
||||
}
|
||||
|
||||
TEST_CASE("A per-variant project value maps onto its base preset's variant layout", "[Preset][ExternalPreset]")
|
||||
{
|
||||
const DynamicPrintConfig defaults = external_default_config(Preset::TYPE_PRINT);
|
||||
DynamicPrintConfig base = defaults;
|
||||
base.set_key_value("print_extruder_id", new ConfigOptionInts({1, 1}));
|
||||
base.set_key_value("print_extruder_variant", new ConfigOptionStrings({"Direct Drive Standard", "Direct Drive High Flow"}));
|
||||
base.set_key_value("outer_wall_speed", new ConfigOptionFloats({200., 300.}));
|
||||
base.set_key_value("inner_wall_speed", new ConfigOptionFloats({250., 350.}));
|
||||
// A project saved before its printer had a High Flow variant.
|
||||
DynamicPrintConfig project;
|
||||
project.set_key_value("print_extruder_id", new ConfigOptionInts({1}));
|
||||
project.set_key_value("print_extruder_variant", new ConfigOptionStrings({"Direct Drive Standard"}));
|
||||
project.set_key_value("outer_wall_speed", new ConfigOptionFloats({100.}));
|
||||
project.set_key_value("inner_wall_speed", new ConfigOptionFloats({150.}));
|
||||
int calls = 0;
|
||||
|
||||
const DynamicPrintConfig config = Preset::load_external_config(Preset::TYPE_PRINT, defaults, project, {"outer_wall_speed"},
|
||||
base_finder(&base, calls));
|
||||
CHECK(config.option<ConfigOptionStrings>("print_extruder_variant")->values ==
|
||||
std::vector<std::string>{"Direct Drive Standard", "Direct Drive High Flow"});
|
||||
// The listed key keeps the project's Standard value and takes High Flow from the base.
|
||||
check_double_vector(config.option<ConfigOptionFloats>("outer_wall_speed")->values, {100., 300.});
|
||||
check_double_vector(config.option<ConfigOptionFloats>("inner_wall_speed")->values, {250., 350.});
|
||||
}
|
||||
|
||||
TEST_CASE("A project's different settings always keep the preset bookkeeping keys", "[Preset][ExternalPreset]")
|
||||
{
|
||||
const std::set<std::string> keys = PresetBundle::project_different_keys(escape_strings_cstyle({"wall_loops", "top_shell_layers"}));
|
||||
for (const char *key : {"wall_loops", "top_shell_layers", "inherits", "print_settings_id", "filament_settings_id", "printer_settings_id"})
|
||||
CHECK(keys.count(key) == 1);
|
||||
CHECK(PresetBundle::project_different_keys(std::string()).count("inherits") == 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user