From c3005c6ba6cad64d43dbb93602eb94b592de4be4 Mon Sep 17 00:00:00 2001 From: Daiyi Peng Date: Thu, 13 Apr 2023 22:13:49 -0700 Subject: [PATCH] Support 'python_format' for `pg.Symbolic.format` method. PiperOrigin-RevId: 524196407 --- pyglove/core/symbolic/base.py | 9 +++++++ pyglove/core/symbolic/dict.py | 21 +++++++++++++-- pyglove/core/symbolic/dict_test.py | 36 ++++++++++++++++++++++++++ pyglove/core/symbolic/list.py | 18 ++++++++++--- pyglove/core/symbolic/list_test.py | 38 ++++++++++++++++++++++++++++ pyglove/core/symbolic/object.py | 1 + pyglove/core/symbolic/object_test.py | 28 ++++++++++++++++++++ 7 files changed, 145 insertions(+), 6 deletions(-) diff --git a/pyglove/core/symbolic/base.py b/pyglove/core/symbolic/base.py index 7b4f086..5813886 100644 --- a/pyglove/core/symbolic/base.py +++ b/pyglove/core/symbolic/base.py @@ -62,8 +62,17 @@ def format(self, compact: bool = False, verbose: bool = True, root_indent: int = 0, + *, + python_format: bool = False, + hide_default_values: bool = False, + hide_missing_values: bool = False, **kwargs) -> str: """Formats this object.""" + kwargs.update({ + 'python_format': python_format, + 'hide_default_values': hide_default_values, + 'hide_missing_values': hide_missing_values, + }) details = object_utils.kvlist_str([ ('parent_path', self.target.sym_path, None), ('path', self.path.path, None), diff --git a/pyglove/core/symbolic/dict.py b/pyglove/core/symbolic/dict.py index c485a46..709eaaf 100644 --- a/pyglove/core/symbolic/dict.py +++ b/pyglove/core/symbolic/dict.py @@ -802,11 +802,14 @@ def format( compact: bool = False, verbose: bool = True, root_indent: int = 0, + *, + python_format: bool = False, hide_default_values: bool = False, hide_missing_values: bool = False, exclude_keys: Optional[Set[str]] = None, cls_name: Optional[str] = None, bracket_type: object_utils.BracketType = object_utils.BracketType.CURLY, + key_as_attribute: bool = False, **kwargs) -> str: """Formats this Dict.""" cls_name = cls_name or '' @@ -848,8 +851,13 @@ def _indent(text, indent): root_indent + 1, hide_default_values=hide_default_values, hide_missing_values=hide_missing_values, + python_format=python_format, **kwargs) - kv_strs.append(f'{k}={v_str}') + if not python_format or key_as_attribute: + kv_strs.append(f'{k}={v_str}') + else: + kv_strs.append(f'\'{k}\': {v_str}') + s.append(', '.join(kv_strs)) s.append(close_bracket) else: @@ -871,8 +879,17 @@ def _indent(text, indent): root_indent + 1, hide_default_values=hide_default_values, hide_missing_values=hide_missing_values, + python_format=python_format, **kwargs) - s.append(_indent(f'{k} = {v_str}', root_indent + 1)) + if not python_format: + # Format in PyGlove's format (default). + s.append(_indent(f'{k} = {v_str}', root_indent + 1)) + elif key_as_attribute: + # Format `pg.Objects` under Python format. + s.append(_indent(f'{k}={v_str}', root_indent + 1)) + else: + # Format regular `pg.Dict` under Python format. + s.append(_indent(f'\'{k}\': {v_str}', root_indent + 1)) s.append('\n') s.append(_indent(close_bracket, root_indent)) return ''.join(s) diff --git a/pyglove/core/symbolic/dict_test.py b/pyglove/core/symbolic/dict_test.py index df4c316..655fd1b 100644 --- a/pyglove/core/symbolic/dict_test.py +++ b/pyglove/core/symbolic/dict_test.py @@ -1783,6 +1783,42 @@ def test_compact(self): 'A(x=2, y=MISSING_VALUE, z={p=[0: None, 1: True], ' 'q=\'foo\', t=\'foo\'})}]}}}') + def test_compact_python_format(self): + self.assertEqual( + self._dict.format(compact=True, python_format=True), + '{\'a1\': 1, \'a2\': {\'b1\': {\'c1\': [{\'d1\': MISSING_VALUE, ' + '\'d2\': True, \'d3\': A(x=2, y=MISSING_VALUE, z={\'p\': [None, True], ' + '\'q\': \'foo\', \'t\': \'foo\'})}]}}}') + + def test_noncompact_python_format(self): + self.assertEqual( + self._dict.format(compact=False, verbose=False, python_format=True), + inspect.cleandoc("""{ + 'a1': 1, + 'a2': { + 'b1': { + 'c1': [ + { + 'd1': MISSING_VALUE(Str()), + 'd2': True, + 'd3': A( + x=2, + y=MISSING_VALUE(Str()), + z={ + 'p': [ + None, + True + ], + 'q': 'foo', + 't': 'foo' + } + ) + } + ] + } + } + }""")) + def test_noncompact_nonverbose(self): self.assertEqual( self._dict.format(compact=False, verbose=False), diff --git a/pyglove/core/symbolic/list.py b/pyglove/core/symbolic/list.py index c39255b..92ead93 100644 --- a/pyglove/core/symbolic/list.py +++ b/pyglove/core/symbolic/list.py @@ -704,6 +704,8 @@ def format( compact: bool = False, verbose: bool = True, root_indent: int = 0, + *, + python_format: bool = False, cls_name: Optional[str] = None, bracket_type: object_utils.BracketType = object_utils.BracketType.SQUARE, **kwargs) -> str: @@ -719,8 +721,12 @@ def _indent(text, indent): kv_strs = [] for idx, elem in enumerate(self): v_str = object_utils.format( - elem, compact, verbose, root_indent + 1, **kwargs) - kv_strs.append(f'{idx}: {v_str}') + elem, compact, verbose, root_indent + 1, + python_format=python_format, **kwargs) + if python_format: + kv_strs.append(v_str) + else: + kv_strs.append(f'{idx}: {v_str}') s.append(', '.join(kv_strs)) s.append(close_bracket) else: @@ -731,8 +737,12 @@ def _indent(text, indent): else: s.append(',\n') v_str = object_utils.format( - elem, compact, verbose, root_indent + 1, **kwargs) - s.append(_indent(f'{idx} : {v_str}', root_indent + 1)) + elem, compact, verbose, root_indent + 1, + python_format=python_format, **kwargs) + if python_format: + s.append(_indent(v_str, root_indent + 1)) + else: + s.append(_indent(f'{idx} : {v_str}', root_indent + 1)) s.append('\n') s.append(_indent(close_bracket, root_indent)) else: diff --git a/pyglove/core/symbolic/list_test.py b/pyglove/core/symbolic/list_test.py index 775ceb4..b73362f 100644 --- a/pyglove/core/symbolic/list_test.py +++ b/pyglove/core/symbolic/list_test.py @@ -1533,6 +1533,44 @@ def test_compact(self): 'A(x=2, y=MISSING_VALUE, z={p=[0: None, 1: True], ' 'q=\'foo\', t=\'foo\'})}]}}}]') + def test_compact_python_format(self): + self.assertEqual( + self._list.format(compact=True, python_format=True), + '[{\'a1\': 1, \'a2\': {\'b1\': {\'c1\': [{\'d1\': MISSING_VALUE, ' + '\'d2\': True, \'d3\': A(x=2, y=MISSING_VALUE, z={\'p\': [None, True], ' + '\'q\': \'foo\', \'t\': \'foo\'})}]}}}]') + + def test_noncompact_python_format(self): + self.assertEqual( + self._list.format(compact=False, verbose=False, python_format=True), + inspect.cleandoc("""[ + { + 'a1': 1, + 'a2': { + 'b1': { + 'c1': [ + { + 'd1': MISSING_VALUE(Str()), + 'd2': True, + 'd3': A( + x=2, + y=MISSING_VALUE(Str()), + z={ + 'p': [ + None, + True + ], + 'q': 'foo', + 't': 'foo' + } + ) + } + ] + } + } + } + ]""")) + def test_noncompact_nonverbose(self): self.assertEqual( self._list.format(compact=False, verbose=False), diff --git a/pyglove/core/symbolic/object.py b/pyglove/core/symbolic/object.py index 8cd96b2..62de2d1 100644 --- a/pyglove/core/symbolic/object.py +++ b/pyglove/core/symbolic/object.py @@ -631,6 +631,7 @@ def format(self, verbose, root_indent, cls_name=self.__class__.__name__, + key_as_attribute=True, bracket_type=object_utils.BracketType.ROUND, **kwargs) diff --git a/pyglove/core/symbolic/object_test.py b/pyglove/core/symbolic/object_test.py index 2e943c3..bdd44a3 100644 --- a/pyglove/core/symbolic/object_test.py +++ b/pyglove/core/symbolic/object_test.py @@ -2595,6 +2595,34 @@ def test_compact(self): 'A(x=[0: A(x=1, y=None), 1: A(x=\'foo\', y={a=A(x=True, y=1.0)})], ' 'y=MISSING_VALUE)') + def test_compact_python_format(self): + self.assertEqual( + self._a.format(compact=True, python_format=True), + 'A(x=[A(x=1, y=None), A(x=\'foo\', y={\'a\': A(x=True, y=1.0)})], ' + 'y=MISSING_VALUE)') + + def test_noncompact_python_format(self): + self.assertEqual( + self._a.format(compact=False, verbose=False, python_format=True), + inspect.cleandoc("""A( + x=[ + A( + x=1, + y=None + ), + A( + x='foo', + y={ + 'a': A( + x=True, + y=1.0 + ) + } + ) + ], + y=MISSING_VALUE(Any()) + )""")) + def test_noncompact_nonverbose(self): self.assertEqual( self._a.format(compact=False, verbose=False),