diff --git a/src/databricks/labs/blueprint/installation.py b/src/databricks/labs/blueprint/installation.py index b60ff60..43de6f1 100644 --- a/src/databricks/labs/blueprint/installation.py +++ b/src/databricks/labs/blueprint/installation.py @@ -632,7 +632,8 @@ def _marshal_dataclass(self, type_ref: type, path: list[str], inst: Any) -> tupl value, ok = self._marshal(hint, [*path, field], raw) if not ok: raise SerdeError(self._explain_why(hint, [*path, field], raw)) - if not value: + # Earlier for boolean fields when the value was False, we would skip it. Which was incorrect + if not value and hint is not bool: continue as_dict[field] = value return as_dict, True @@ -936,7 +937,7 @@ def _dump_csv(raw: list[JsonObject], type_ref: type) -> bytes: if not isinstance(as_dict, dict): raise SerdeError(f"Expecting a list of dictionaries. Got {as_dict}") for k, v in as_dict.items(): - if not v: + if not v and v is not False: continue non_empty_keys.add(k) buffer = io.StringIO() diff --git a/tests/unit/test_installation.py b/tests/unit/test_installation.py index 2eb6811..4f0cf89 100644 --- a/tests/unit/test_installation.py +++ b/tests/unit/test_installation.py @@ -761,3 +761,25 @@ class ForwardReferencingClass: loaded = installation.load(ForwardReferencingClass, filename="saved.yml") assert instance == loaded + + +def test_bool_attribute() -> None: + @dataclass(kw_only=True) + class BooleanAttributeClass: + __file__ = "config.yml" + __version__ = 3 + skip_validation: bool + sdk_config: JsonValue + + instance_false = BooleanAttributeClass(skip_validation=False, sdk_config={"warehouse_id": "8xc123456"}) + installation = MockInstallation() + installation.save(instance_false) + + loaded_false = installation.load(BooleanAttributeClass) + assert instance_false == loaded_false + + instance_true = BooleanAttributeClass(skip_validation=True, sdk_config={"warehouse_id": "9xc1234567"}) + installation.save(instance_true) + + loaded_true = installation.load(BooleanAttributeClass) + assert instance_true == loaded_true