Help to improve to this custom dict printing (or formatting) function?

Been trying to write a fn that prints dictionaries as I like it. There surely are libraries but wanted to do it as an exercise.

I wonder what next-step improvements you’d suggest, or how would you re-write it, without going too far into expert-land?

(Maybe the first improvement is the name, but just leave that aside for now.)

The function is used within a logger class (that inherits from Logger), so it’s not logging there itself.

"""Format dict for pretty printing."""

from collections.abc import Callable

def pp_dict(
  config: dict,
  max_depth: int = 5,
  *,
  _indent: int = 0,
) -> str:
  """Recursively clean up config classes and names for logging.

  Args:
    config: full configuration object or dictionary.
    max_depth: how far to go in nested dictionaries
    _indent: how many spaces to indent at sublevels (internal use only.)

  """
  to_join = []
  for k, v in config.items():
    new_val = v
    new_key = k
    if isinstance(v, Callable):
      new_val = v.__name__
    elif isinstance(v, dict):
      new_key = new_key.capitalize()
      to_join.append(f"\n{new_key}\n")
      if max_depth > 0:
        to_join.append(f"{pp_dict(v,max_depth=max_depth-1, _indent=_indent+2)}")
      else:
        msg = f"max_depth={max_depth} was reached due to deeply nested dicts."
        raise MaxDepthReachedError(msg)
      continue
    elif v is None:
      new_val = v.__class__.__name__[:4]
    elif isinstance(v, bool | str | int | float | tuple):
      new_val = v
    to_join.append(f"{new_key.rjust(_indent)} = {new_val}")
  return "\n".join(to_join)


class MaxDepthReachedError(Exception):
  pass

Just realised max_depth’s value doesn’t really make sense, it’d be 0 when erroring. Leaving it there though.

What does this need to do, that pprint doesn’t already do?

1 Like

I know pprint, but as I said in the OP:

There surely are libraries but wanted to do it as an exercise.

It does not handle class names by default, nor prints None as I prefer to see, nor capitalises the keys of nested dictionaries.

But aside from that, I’m just learning python so that’s why I find fun to re-invent (a lot worse) things.

1 Like

Keep in mind the possibility of loops in your data structure. Python and pprint already have ways of handling that:

>>> x = {'a': None}
>>> x['a'] = x
>>> x
{'a': {...}}
>>> import pprint
>>> pprint.pprint(x)
{'a': <Recursion on dict with id=4308398400>}