From c0950a9698ee71c354c90ed822c3b9ba442bc22b Mon Sep 17 00:00:00 2001 From: benflexcompute Date: Tue, 21 Jul 2026 15:17:08 -0400 Subject: [PATCH] [Hotfix 25.9] fix(updater): rename CustomVolume boundaries to bounding_entities everywhere _to_25_9_2 renamed `boundaries` -> `bounding_entities` only under meshing.volume_zones/zones, leaving CustomVolume dicts stale in model entities, parent_volume, UDD output_target and asset-cache draft_entities. Add _to_25_9_10 with a whole-dict recursive rename (run-once sentinel, stripped before return) and bump version to 25.9.10. Co-Authored-By: Claude Fable 5 --- .../component/simulation/framework/updater.py | 42 ++++++++++++++ flow360/version.py | 2 +- pyproject.toml | 2 +- tests/simulation/test_updater.py | 57 +++++++++++++++++++ tests/test_current_flow360_version.py | 2 +- 5 files changed, 102 insertions(+), 3 deletions(-) diff --git a/flow360/component/simulation/framework/updater.py b/flow360/component/simulation/framework/updater.py index b4ab1edb0..2d5c5c2a8 100644 --- a/flow360/component/simulation/framework/updater.py +++ b/flow360/component/simulation/framework/updater.py @@ -836,6 +836,46 @@ def _to_25_9_5(params_as_dict): return _convert_total_pressure_expression_from_ratio_to_nondim(params_as_dict) +_CUSTOM_VOLUME_RENAME_APPLIED_KEY = "__custom_volume_bounding_entities_applied" + + +def _rename_custom_volume_boundaries_everywhere(params_as_dict): + """Rename ``boundaries`` to ``bounding_entities`` on every ``CustomVolume`` dict. + + ``_to_25_9_2`` only handled ``meshing.volume_zones``/``meshing.zones``, missing + CustomVolume dicts everywhere else (asset cache draft entities, model entities, + ``parent_volume``, ``output_target``). This walks the whole params dict instead. + + This function is referenced by one milestone per release line. A sentinel key + on the dict itself prevents redundant re-walks within one updater() call; + ``updater()`` strips it before returning. + """ + if params_as_dict.get(_CUSTOM_VOLUME_RENAME_APPLIED_KEY): + return params_as_dict + params_as_dict[_CUSTOM_VOLUME_RENAME_APPLIED_KEY] = True + + def _walk(node): + if isinstance(node, dict): + if ( + node.get("private_attribute_entity_type_name") == "CustomVolume" + and "boundaries" in node + and "bounding_entities" not in node + ): + node["bounding_entities"] = node.pop("boundaries") + for value in node.values(): + _walk(value) + elif isinstance(node, list): + for item in node: + _walk(item) + + _walk(params_as_dict) + return params_as_dict + + +def _to_25_9_10(params_as_dict): + return _rename_custom_volume_boundaries_everywhere(params_as_dict) + + VERSION_MILESTONES = [ (Flow360Version("24.11.1"), _to_24_11_1), (Flow360Version("24.11.7"), _to_24_11_7), @@ -861,6 +901,7 @@ def _to_25_9_5(params_as_dict): (Flow360Version("25.9.2"), _to_25_9_2), (Flow360Version("25.9.3"), _to_25_9_3), (Flow360Version("25.9.5"), _to_25_9_5), + (Flow360Version("25.9.10"), _to_25_9_10), ] # A list of the Python API version tuple with their corresponding updaters. @@ -951,5 +992,6 @@ def updater(version_from, version_to, params_as_dict) -> dict: _to_version = re.search(r"_to_(\d+_\d+_\d+)", fun.__name__).group(1) log.debug(f"Updating input SimulationParam to {_to_version}...") params_as_dict = fun(params_as_dict) + params_as_dict.pop(_CUSTOM_VOLUME_RENAME_APPLIED_KEY, None) params_as_dict["version"] = str(version_to) return params_as_dict diff --git a/flow360/version.py b/flow360/version.py index 46904fc9a..d2309e26e 100644 --- a/flow360/version.py +++ b/flow360/version.py @@ -2,5 +2,5 @@ version """ -__version__ = "25.9.9" +__version__ = "25.9.10" __solver_version__ = "release-25.9" diff --git a/pyproject.toml b/pyproject.toml index 8e6cee0dc..b80b4406f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "flow360" -version = "v25.9.9" +version = "v25.9.10" description = "Flow360 Python Client" authors = ["Flexcompute "] diff --git a/tests/simulation/test_updater.py b/tests/simulation/test_updater.py index 3f2ca322d..dde09a355 100644 --- a/tests/simulation/test_updater.py +++ b/tests/simulation/test_updater.py @@ -2331,3 +2331,60 @@ def test_updater_total_pressure_no_double_conversion_across_branches(): assert params_new["version"] == "25.9.5" assert params_new["models"][0]["spec"]["value"] == "(1.0 + 0.5 * sin(y)) / 1.4" + + +def test_updater_to_25_9_10_custom_volume_rename_everywhere(): + """Test 25.9.10 updater renames boundaries -> bounding_entities on CustomVolume + dicts outside meshing.volume_zones, which _to_25_9_2 missed.""" + + def custom_volume(): + return { + "private_attribute_entity_type_name": "CustomVolume", + "name": "cv", + "boundaries": { + "stored_entities": [ + {"private_attribute_entity_type_name": "Surface", "name": "face1"} + ] + }, + } + + params_as_dict = { + "version": "25.9.3", + "meshing": { + "volume_zones": [ + {"type": "CustomZones", "entities": {"stored_entities": [custom_volume()]}} + ], + }, + "models": [ + { + "type": "Rotation", + "entities": {"stored_entities": [custom_volume()]}, + "parent_volume": custom_volume(), + } + ], + "user_defined_dynamics": [{"output_target": custom_volume()}], + "private_attribute_asset_cache": { + "project_entity_info": {"draft_entities": [custom_volume()]} + }, + } + + params_new = updater( + version_from="25.9.3", + version_to="25.9.10", + params_as_dict=params_as_dict, + ) + + renamed = [ + params_new["meshing"]["volume_zones"][0]["entities"]["stored_entities"][0], + params_new["models"][0]["entities"]["stored_entities"][0], + params_new["models"][0]["parent_volume"], + params_new["user_defined_dynamics"][0]["output_target"], + params_new["private_attribute_asset_cache"]["project_entity_info"]["draft_entities"][0], + ] + for cv in renamed: + assert "boundaries" not in cv + assert cv["bounding_entities"]["stored_entities"][0]["name"] == "face1" + + assert params_new["version"] == "25.9.10" + # The run-once sentinel must not leak into the returned dict. + assert "__custom_volume_bounding_entities_applied" not in params_new diff --git a/tests/test_current_flow360_version.py b/tests/test_current_flow360_version.py index fc03edf03..df04e99a3 100644 --- a/tests/test_current_flow360_version.py +++ b/tests/test_current_flow360_version.py @@ -2,4 +2,4 @@ def test_version(): - assert __version__ == "25.9.9" + assert __version__ == "25.9.10"