From 1655295372986f538f63c16aba757249836e19fd Mon Sep 17 00:00:00 2001 From: ZealSV Date: Thu, 14 May 2026 15:01:37 -0700 Subject: [PATCH] fix(sagemaker-core): preserve falsy values in serialize() output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The walrus check in _serialize_dict and _serialize_list silently dropped False / 0 / "" along with None / Unassigned, because all of them are falsy. Boolean parameters that should reach the wire as False were instead omitted, causing the server to apply its own default (often True), which led to confusing validation errors that contradicted the caller's input. Concrete failure: AIRecommendationJob.create(optimize_model=False) silently sent OptimizeModel=True, then failed with a server message about a missing DatasetConfig — a requirement that only applies when OptimizeModel is True. Replace the walrus truthy guard with an explicit `is not None` check. serialize() already returns None for both None and Unassigned (utils.py line 512), so this preserves the "drop unset fields" semantics while correctly retaining valid falsy payloads. Adds two regression tests covering False / 0 / "" preservation and None / Unassigned removal. --- sagemaker-core/src/sagemaker/core/utils/utils.py | 10 +++++++--- sagemaker-core/tests/unit/generated/test_utils.py | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/sagemaker-core/src/sagemaker/core/utils/utils.py b/sagemaker-core/src/sagemaker/core/utils/utils.py index 2881695969..b22f662cc0 100644 --- a/sagemaker-core/src/sagemaker/core/utils/utils.py +++ b/sagemaker-core/src/sagemaker/core/utils/utils.py @@ -538,9 +538,11 @@ def _serialize_dict(value: Dict) -> dict: dict: The serialized dict """ serialized_dict = {} + # Drop only Unassigned/None; preserve valid falsy values like False, 0, "". for k, v in value.items(): - if serialize_result := serialize(v): - serialized_dict.update({k: serialize_result}) + serialize_result = serialize(v) + if serialize_result is not None: + serialized_dict[k] = serialize_result return serialized_dict @@ -555,8 +557,10 @@ def _serialize_list(value: List) -> list: list: The serialized list """ serialized_list = [] + # Drop only Unassigned/None; preserve valid falsy values like False, 0, "". for v in value: - if serialize_result := serialize(v): + serialize_result = serialize(v) + if serialize_result is not None: serialized_list.append(serialize_result) return serialized_list diff --git a/sagemaker-core/tests/unit/generated/test_utils.py b/sagemaker-core/tests/unit/generated/test_utils.py index 44856d17d5..0928f09b68 100644 --- a/sagemaker-core/tests/unit/generated/test_utils.py +++ b/sagemaker-core/tests/unit/generated/test_utils.py @@ -353,6 +353,20 @@ def test_serialize_method_returns_correct_data(): assert serialized_data["S3Uri"] == "s3/uri" +def test_serialize_preserves_falsy_dict_values(): + # Regression: previously False / 0 / "" were stripped along with None. + assert serialize({"k": False}) == {"k": False} + assert serialize({"k": 0}) == {"k": 0} + assert serialize({"k": ""}) == {"k": ""} + assert serialize({"k": None}) == {} + assert serialize({"k": Unassigned()}) == {} + + +def test_serialize_preserves_falsy_list_values(): + assert serialize([False, 0, ""]) == [False, 0, ""] + assert serialize([None, "x", Unassigned(), 1]) == ["x", 1] + + def test_serialize_method_nested_shape(): trial_component_parameters = { "test_num_value": TrialComponentParameterValue(number_value=1),