From 1d3ab93d10dc206152e40a67a1631d30908456c9 Mon Sep 17 00:00:00 2001 From: devteamaegis Date: Sun, 2 Aug 2026 16:25:07 -0400 Subject: [PATCH] fix(text): don't crash on --query lists mixing scalars and objects _format_list treats a list as a list of dicts when *any* element is a dict, but _all_scalar_keys then called .items() on every element. A --query multi-select list such as '[InstanceId, State]' returns a scalar alongside an object, so --output text exited 255 with AttributeError: 'str' object has no attribute 'items'. Skip non-dict elements when collecting the scalar keys; _format_text already renders them on their own. --- .../bugfix-text-output-mixed-list.json | 5 +++++ awscli/text.py | 5 +++++ tests/unit/test_text.py | 16 ++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 .changes/next-release/bugfix-text-output-mixed-list.json diff --git a/.changes/next-release/bugfix-text-output-mixed-list.json b/.changes/next-release/bugfix-text-output-mixed-list.json new file mode 100644 index 000000000000..5de75f17fac6 --- /dev/null +++ b/.changes/next-release/bugfix-text-output-mixed-list.json @@ -0,0 +1,5 @@ +{ + "category": "``text`` output", + "description": "Fix ``AttributeError`` when ``--output text`` renders a list that contains both a scalar and an object, which a ``--query`` multi-select list such as ``[InstanceId, State]`` produces", + "type": "bugfix" +} diff --git a/awscli/text.py b/awscli/text.py index 6b915b0f8f2b..8ded80bb3a82 100644 --- a/awscli/text.py +++ b/awscli/text.py @@ -85,6 +85,11 @@ def _format_dict(scalar_keys, item, identifier, stream): def _all_scalar_keys(list_of_dicts): keys_seen = set() for item_dict in list_of_dicts: + if not isinstance(item_dict, dict): + # The list is only required to contain *at least* one dict, + # so skip over any elements that aren't dicts. They are + # rendered on their own by _format_text. + continue for key, value in item_dict.items(): if not isinstance(value, (dict, list)): keys_seen.add(key) diff --git a/tests/unit/test_text.py b/tests/unit/test_text.py index c08e2e23033d..0e748286d23a 100644 --- a/tests/unit/test_text.py +++ b/tests/unit/test_text.py @@ -219,6 +219,22 @@ def test_deeply_nested_with_identifier(self): 'FOO\th\n' ) + def test_dicts_mixed_with_scalars(self): + # A --query multi-select list such as '[InstanceId, State]' + # produces a list holding both a scalar and a dict. + self.assert_text_renders_to( + ['i-123', dict(Code=16, Name='running')], + 'i-123\n' + '16\trunning\n' + ) + + def test_dicts_mixed_with_lists(self): + self.assert_text_renders_to( + [['a', 'b'], dict(Code=16, Name='running')], + 'a\tb\n' + '16\trunning\n' + ) + if __name__ == '__main__': unittest.main()