Skip to content

Commit ef2e4d0

Browse files
actually pretty printing that doesn't get all bunched up all over the console
1 parent 965cf8e commit ef2e4d0

File tree

1 file changed

+39
-11
lines changed

1 file changed

+39
-11
lines changed

linkml_runtime/utils/yamlutils.py

+39-11
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from json import JSONDecoder
33
from typing import Union, Any, List, Optional, Type, Callable, Dict
44
from pprint import pformat
5+
import textwrap
6+
import re
57

68
import yaml
79
from deprecated.classic import deprecated
@@ -279,19 +281,45 @@ def MissingRequiredField(self, field_name: str) -> None:
279281
raise ValueError(f"{field_name} must be supplied")
280282

281283
def __repr__(self):
282-
"""Only reformat 1-layer deep to preserve __repr__ of child objects"""
283-
res = {}
284-
for key, val in items(self):
285-
if val == [] or val == {} or val is None:
286-
continue
287-
res[key] = val
288-
return self.__class__.__name__ + '(' + pformat(res, indent=2,
289-
compact=True, sort_dicts=False) + ')'
284+
return _pformat(items(self), self.__class__.__name__)
290285

291286
def __str__(self):
292-
"""Dump everything into a dict, recursively, stringifying it all"""
293-
res = remove_empty_items(self)
294-
return self.__class__.__name__ + '(' + pformat(res, indent=2, compact=True) + ')'
287+
return repr(self)
288+
289+
def _pformat(fields:dict, cls_name:str, indent:str = ' ') -> str:
290+
"""
291+
pretty format the fields of the items of a ``YAMLRoot`` object without the wonky indentation of pformat.
292+
see ``YAMLRoot.__repr__``.
293+
294+
formatting is similar to black - items at similar levels of nesting have similar levels of indentation,
295+
rather than getting placed at essentially random levels of indentation depending on what came before them.
296+
"""
297+
res = []
298+
total_len = 0
299+
for key, val in fields:
300+
if val == [] or val == {} or val is None:
301+
continue
302+
# pformat handles everything else that isn't a YAMLRoot object, but it sure does look ugly
303+
# use it to split lines and as the thing of last resort, but otherwise indent = 0, we'll do that
304+
val_str = pformat(val, indent=0, compact=True, sort_dicts=False)
305+
# now we indent everything except the first line by indenting and then using regex to remove just the first indent
306+
val_str = re.sub(rf'\A{re.escape(indent)}', '', textwrap.indent(val_str, indent))
307+
# now recombine with the key in a format that can be re-eval'd into an object if indent is just whitespace
308+
val_str = f"'{key}': " + val_str
309+
310+
# count the total length of this string so we know if we need to linebreak or not later
311+
total_len += len(val_str)
312+
res.append(val_str)
313+
314+
if total_len > 80:
315+
inside = ',\n'.join(res)
316+
# we indent twice - once for the inner contents of every inner object, and one to
317+
# offset from the root element. that keeps us from needing to be recursive except for the
318+
# single pformat call
319+
inside = textwrap.indent(inside, indent)
320+
return cls_name + '({\n' + inside + '\n})'
321+
else:
322+
return cls_name + '({' + ', '.join(res) + '})'
295323

296324

297325
def root_representer(dumper: yaml.Dumper, data: YAMLRoot):

0 commit comments

Comments
 (0)