diff --git a/fire/core.py b/fire/core.py index 8e23e76b..7dabe5c3 100644 --- a/fire/core.py +++ b/fire/core.py @@ -351,6 +351,9 @@ def _OneLineResult(result): if inspect.ismodule(result): return f'' + if inspectutils.IsNamedTuple(result): + return json.dumps(result._asdict(), ensure_ascii=False) + try: # Don't force conversion to ascii. return json.dumps(result, ensure_ascii=False) diff --git a/fire/core_test.py b/fire/core_test.py index f48d6e2d..5d85cb56 100644 --- a/fire/core_test.py +++ b/fire/core_test.py @@ -14,6 +14,7 @@ """Tests for the core module.""" +import collections from unittest import mock from fire import core @@ -137,6 +138,12 @@ def testPrintOrderedDict(self): with self.assertOutputMatches(stdout='{}'): core.Fire(tc.OrderedDictionary, command=['empty']) + def testPrintDictOfNamedTuples(self): + point = collections.namedtuple('Point', ['x', 'y']) + data = {'a': point(1, 2), 'b': point(3, 4)} + with self.assertOutputMatches(stdout=r'a:\s+\{"x": 1, "y": 2\}', stderr=None): + core.Fire(data, command=[]) + def testPrintNamedTupleField(self): with self.assertOutputMatches(stdout='11', stderr=None): core.Fire(tc.NamedTuple, command=['point', 'x']) diff --git a/fire/value_types.py b/fire/value_types.py index 81308973..36f032f6 100644 --- a/fire/value_types.py +++ b/fire/value_types.py @@ -50,7 +50,8 @@ def IsSimpleGroup(component): """ assert isinstance(component, dict) for unused_key, value in component.items(): - if not IsValue(value) and not isinstance(value, (list, dict)): + if (not IsValue(value) and not isinstance(value, (list, dict)) + and not inspectutils.IsNamedTuple(value)): return False return True