From daf5abacf1436ea8d21b53153fbf5b07bdcafe6a Mon Sep 17 00:00:00 2001 From: Gin3601 <2405559452@qq.com> Date: Wed, 20 May 2026 19:06:57 +0800 Subject: [PATCH] fix: coerce repair metadata booleans --- repair/repair_utils.py | 28 ++++++++++++++++++++++---- tests/test_repair_utils.py | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/repair/repair_utils.py b/repair/repair_utils.py index 8003928..e1dbf20 100644 --- a/repair/repair_utils.py +++ b/repair/repair_utils.py @@ -41,7 +41,7 @@ def normalize_model_info(model_info: dict[str, Any] | str | None) -> dict[str, A return { "model_family": _normalize_model_family(raw_family), "model_role": str(raw.get("model_role") or raw.get("role") or "unknown"), - "supports_inpaint_native": bool(raw.get("supports_inpaint_native", False)), + "supports_inpaint_native": _coerce_bool(raw.get("supports_inpaint_native"), False), } @@ -61,12 +61,13 @@ def normalize_repair_info(repair_info: dict[str, Any] | str | None) -> dict[str, info["mask_grow"] = _coerce_int(info.get("mask_grow"), 8) info["mask_blur"] = _coerce_float(info.get("mask_blur"), 8.0) info["mask_threshold"] = _coerce_float(info.get("mask_threshold"), 0.5) - info["invert_mask"] = bool(info.get("invert_mask", False)) + info["invert_mask"] = _coerce_bool(info.get("invert_mask"), False) info["recommended_denoise"] = _coerce_float(info.get("recommended_denoise"), 0.55) info["model_family"] = _normalize_model_family(info.get("model_family") or model_info["model_family"]) info["model_role"] = str(info.get("model_role") or model_info["model_role"]) - info["supports_inpaint_native"] = bool( - info.get("supports_inpaint_native", model_info["supports_inpaint_native"]) + info["supports_inpaint_native"] = _coerce_bool( + info.get("supports_inpaint_native", model_info["supports_inpaint_native"]), + model_info["supports_inpaint_native"], ) info["repair_payload_version"] = str(info.get("repair_payload_version") or "1.0") info["warnings"] = _normalize_warning_list(info.get("warnings")) @@ -280,6 +281,25 @@ def _coerce_float(value: Any, default: float) -> float: return default +def _coerce_bool(value: Any, default: bool) -> bool: + if value is None: + return default + if isinstance(value, bool): + return value + if isinstance(value, (int, float)): + return value != 0 + if isinstance(value, str): + lowered = value.strip().lower() + if lowered in {"", "none"}: + return default + if lowered in {"true", "1", "yes", "on"}: + return True + if lowered in {"false", "0", "no", "off"}: + return False + return default + return bool(value) + + def _normalize_box(value: Any) -> tuple[int, int, int, int] | None: if value is None: return None diff --git a/tests/test_repair_utils.py b/tests/test_repair_utils.py index 37e517f..6cb0076 100644 --- a/tests/test_repair_utils.py +++ b/tests/test_repair_utils.py @@ -32,6 +32,22 @@ class TestRepairUtils(unittest.TestCase): model_info = utils.normalize_model_info({"model_family": "SD15"}) self.assertEqual(model_info["model_family"], "SD1.5") + def test_normalize_model_info_coerces_string_booleans(self): + utils = load_repair_utils() + + self.assertFalse( + utils.normalize_model_info({"supports_inpaint_native": "false"})["supports_inpaint_native"] + ) + self.assertFalse( + utils.normalize_model_info({"supports_inpaint_native": "0"})["supports_inpaint_native"] + ) + self.assertTrue( + utils.normalize_model_info({"supports_inpaint_native": "true"})["supports_inpaint_native"] + ) + self.assertTrue( + utils.normalize_model_info({"supports_inpaint_native": 1})["supports_inpaint_native"] + ) + def test_canonicalized_family_feeds_sd_classic_adapter_resolution(self): utils = load_repair_utils() @@ -106,6 +122,22 @@ class TestRepairUtils(unittest.TestCase): "vae_inpaint", ) + def test_resolve_repair_kernel_downgrades_explicit_native_fill_when_unsupported(self): + utils = load_repair_utils() + + kernel, warnings = utils.resolve_repair_kernel( + "native_fill", + scope="region", + task_hint="repair", + mask_area_ratio=0.05, + model_info={"supports_inpaint_native": "false"}, + ) + self.assertEqual(kernel, "vae_inpaint") + self.assertEqual( + warnings, + ["native_fill requested but unsupported; falling back to vae_inpaint"], + ) + def test_recommend_denoise_applies_required_rules(self): utils = load_repair_utils() @@ -176,6 +208,14 @@ class TestRepairUtils(unittest.TestCase): info = utils.normalize_repair_info({"model_family": "SD15", "repair_scope": "region"}) self.assertEqual(info["model_family"], "SD1.5") + def test_normalize_repair_info_coerces_string_boolean_invert_mask(self): + utils = load_repair_utils() + + self.assertFalse(utils.normalize_repair_info({"invert_mask": "false"})["invert_mask"]) + self.assertFalse(utils.normalize_repair_info({"invert_mask": "0"})["invert_mask"]) + self.assertTrue(utils.normalize_repair_info({"invert_mask": "true"})["invert_mask"]) + self.assertTrue(utils.normalize_repair_info({"invert_mask": 1})["invert_mask"]) + if __name__ == "__main__": unittest.main()