From 269a4e69dd371dc349b67741d6826f788b5ff700 Mon Sep 17 00:00:00 2001 From: Louise Fox <208544511+folouiseAWS@users.noreply.github.com> Date: Tue, 16 Dec 2025 17:16:17 -0800 Subject: [PATCH 1/2] fix: improve About dialog YAML key formatting for nested structures - Add recursive _make_keys_human_readable method to transform nested dict keys - Add unit tests for the key transformation function This fix ensures nested structures like deadline_dep_versions and additional_info have human-readable keys at all levels. Signed-off-by: Louise Fox <208544511+folouiseAWS@users.noreply.github.com> --- .../client/ui/dialogs/_about_dialog.py | 22 +++- .../deadline_client/ui/dialogs/__init__.py | 1 + .../ui/dialogs/test_about_dialog.py | 120 ++++++++++++++++++ 3 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 test/unit/deadline_client/ui/dialogs/__init__.py create mode 100644 test/unit/deadline_client/ui/dialogs/test_about_dialog.py diff --git a/src/deadline/client/ui/dialogs/_about_dialog.py b/src/deadline/client/ui/dialogs/_about_dialog.py index 892a79cd8..3d0ec9035 100644 --- a/src/deadline/client/ui/dialogs/_about_dialog.py +++ b/src/deadline/client/ui/dialogs/_about_dialog.py @@ -88,6 +88,23 @@ def _build_ui(self): self.setLayout(layout) + def _make_keys_human_readable(self, data): + """ + Recursively replace underscores with spaces in dictionary keys. + + Args: + data: The data structure to process (dict, list, or scalar value) + + Returns: + The data structure with all dictionary keys made human-readable + """ + if isinstance(data, dict): + return {k.replace("_", " "): self._make_keys_human_readable(v) for k, v in data.items()} + elif isinstance(data, list): + return [self._make_keys_human_readable(item) for item in data] + else: + return data + def _format_version_info(self) -> str: """ Combine submitter and version information for display. @@ -102,7 +119,10 @@ def _format_version_info(self) -> str: combined_info = {**submitter_dict, **env_data} - yaml_str = yaml.dump(combined_info, indent=4, sort_keys=False) + # Replace underscores with spaces in keys for user-friendly display (recursively) + friendly_info = self._make_keys_human_readable(combined_info) + + yaml_str = yaml.dump(friendly_info, indent=4, sort_keys=False) return yaml_str def _format_for_copy(self) -> str: diff --git a/test/unit/deadline_client/ui/dialogs/__init__.py b/test/unit/deadline_client/ui/dialogs/__init__.py new file mode 100644 index 000000000..8d929cc86 --- /dev/null +++ b/test/unit/deadline_client/ui/dialogs/__init__.py @@ -0,0 +1 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/test/unit/deadline_client/ui/dialogs/test_about_dialog.py b/test/unit/deadline_client/ui/dialogs/test_about_dialog.py new file mode 100644 index 000000000..cabe2a58d --- /dev/null +++ b/test/unit/deadline_client/ui/dialogs/test_about_dialog.py @@ -0,0 +1,120 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +""" +Tests for the _make_keys_human_readable function in _about_dialog.py. + +These tests verify that nested dictionary keys are properly transformed +to be human-readable by replacing underscores with spaces. +""" + +import pytest + + +def _make_keys_human_readable(data): + """ + Recursively replace underscores with spaces in dictionary keys. + + This is a copy of the function from _about_dialog.py for testing purposes, + to avoid Qt import dependencies. + """ + if isinstance(data, dict): + return {k.replace("_", " "): _make_keys_human_readable(v) for k, v in data.items()} + elif isinstance(data, list): + return [_make_keys_human_readable(item) for item in data] + else: + return data + + +@pytest.mark.parametrize( + "input_data,expected", + [ + pytest.param( + {"some_key": "value", "another_key": 123}, + {"some key": "value", "another key": 123}, + id="flat_dict", + ), + pytest.param( + {"outer_key": {"inner_key": "value", "another_inner_key": 456}}, + {"outer key": {"inner key": "value", "another inner key": 456}}, + id="nested_dict", + ), + pytest.param( + {"level_one": {"level_two": {"level_three": {"deep_key": "deep_value"}}}}, + {"level one": {"level two": {"level three": {"deep key": "deep_value"}}}}, + id="deeply_nested_dict", + ), + pytest.param( + {"items_list": [{"item_name": "first"}, {"item_name": "second"}]}, + {"items list": [{"item name": "first"}, {"item name": "second"}]}, + id="list_with_dicts", + ), + pytest.param( + {"my_list": [1, 2, 3, "four_five"]}, + {"my list": [1, 2, 3, "four_five"]}, + id="list_of_scalars", + ), + pytest.param( + {"normalkey": "value", "AnotherKey": 123}, + {"normalkey": "value", "AnotherKey": 123}, + id="keys_without_underscores", + ), + pytest.param({}, {}, id="empty_dict"), + pytest.param([], [], id="empty_list"), + ], +) +def test_make_keys_human_readable(input_data, expected): + """Test that _make_keys_human_readable correctly transforms dictionary keys.""" + result = _make_keys_human_readable(input_data) + assert result == expected + + +@pytest.mark.parametrize( + "scalar_value", + [ + pytest.param("string_value", id="string"), + pytest.param(123, id="int"), + pytest.param(45.67, id="float"), + pytest.param(True, id="bool"), + pytest.param(None, id="none"), + ], +) +def test_scalar_values_unchanged(scalar_value): + """Test that scalar values pass through unchanged.""" + result = _make_keys_human_readable(scalar_value) + assert result == scalar_value + + +def test_mixed_nested_structure(): + """Test complex structure with dicts, lists, and scalar values.""" + data = { + "deadline_dep_versions": { + "deadline_cloud": "1.0.0", + "boto3_stubs": "1.2.3", + }, + "additional_info": { + "loaded_plugins": [ + {"plugin_name": "Plugin A", "plugin_version": "1.0"}, + {"plugin_name": "Plugin B", "plugin_version": "2.0"}, + ], + "render_engine": "Cycles", + }, + "simple_value": "test", + } + + expected = { + "deadline dep versions": { + "deadline cloud": "1.0.0", + "boto3 stubs": "1.2.3", + }, + "additional info": { + "loaded plugins": [ + {"plugin name": "Plugin A", "plugin version": "1.0"}, + {"plugin name": "Plugin B", "plugin version": "2.0"}, + ], + "render engine": "Cycles", + }, + "simple value": "test", + } + + result = _make_keys_human_readable(data) + assert result == expected From ddfbad5cef6e4db6752e0b72392ffecc57fb8541 Mon Sep 17 00:00:00 2001 From: Louise Fox <208544511+folouiseAWS@users.noreply.github.com> Date: Thu, 18 Dec 2025 09:26:04 -0800 Subject: [PATCH 2/2] refactor: import _make_keys_human_readable in test instead of duplicating Signed-off-by: Louise Fox <208544511+folouiseAWS@users.noreply.github.com> --- .../client/ui/dialogs/_about_dialog.py | 10 +++++++--- .../ui/dialogs/test_about_dialog.py | 19 ++++++------------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/deadline/client/ui/dialogs/_about_dialog.py b/src/deadline/client/ui/dialogs/_about_dialog.py index 3d0ec9035..517be5f8b 100644 --- a/src/deadline/client/ui/dialogs/_about_dialog.py +++ b/src/deadline/client/ui/dialogs/_about_dialog.py @@ -88,7 +88,8 @@ def _build_ui(self): self.setLayout(layout) - def _make_keys_human_readable(self, data): + @staticmethod + def _make_keys_human_readable(data): """ Recursively replace underscores with spaces in dictionary keys. @@ -99,9 +100,12 @@ def _make_keys_human_readable(self, data): The data structure with all dictionary keys made human-readable """ if isinstance(data, dict): - return {k.replace("_", " "): self._make_keys_human_readable(v) for k, v in data.items()} + return { + k.replace("_", " "): _AboutDialog._make_keys_human_readable(v) + for k, v in data.items() + } elif isinstance(data, list): - return [self._make_keys_human_readable(item) for item in data] + return [_AboutDialog._make_keys_human_readable(item) for item in data] else: return data diff --git a/test/unit/deadline_client/ui/dialogs/test_about_dialog.py b/test/unit/deadline_client/ui/dialogs/test_about_dialog.py index cabe2a58d..1e6e500cd 100644 --- a/test/unit/deadline_client/ui/dialogs/test_about_dialog.py +++ b/test/unit/deadline_client/ui/dialogs/test_about_dialog.py @@ -9,20 +9,13 @@ import pytest +try: + from deadline.client.ui.dialogs._about_dialog import _AboutDialog -def _make_keys_human_readable(data): - """ - Recursively replace underscores with spaces in dictionary keys. - - This is a copy of the function from _about_dialog.py for testing purposes, - to avoid Qt import dependencies. - """ - if isinstance(data, dict): - return {k.replace("_", " "): _make_keys_human_readable(v) for k, v in data.items()} - elif isinstance(data, list): - return [_make_keys_human_readable(item) for item in data] - else: - return data + _make_keys_human_readable = _AboutDialog._make_keys_human_readable +except ImportError: + # The tests in this file should be skipped if Qt UI related modules cannot be loaded + pytest.importorskip("deadline.client.ui.dialogs._about_dialog") @pytest.mark.parametrize(