docs: def auto_str(__repr__=False):
      """
      Use this decorator to auto implement __str__() and optionally __repr__() methods on classes.
  
      Args:
          __repr__ (bool): If set to true, the decorator will auto-implement the __repr__() method as
              well.
  
      Returns:
          callable: Decorating function.
  
      Note:
          There are known issues with self referencing (self.s = self). Recursion will be identified
          by the python interpreter and will do no harm, but it will actually not work.
          A eval(class.__repr__()) will obviously not work, when there are attributes that are not
          part of the __init__'s arguments.
  
      Example:
          >>> @auto_str(__repr__=True)
          ... class Demo(object):
          ...    def __init__(self, i=0, s="a", l=None, t=None):
          ...        self.i = i
          ...        self.s = s
          ...        self.l = l
          ...        self.t = t
          >>> dut = Demo(10, 'abc', [1, 2, 3], (1,2,3))
          >>> print(dut.__str__())
          Demo(i=10, l=[1, 2, 3], s='abc', t=(1, 2, 3))
          >>> print(eval(dut.__repr__()).__str__())
          Demo(i=10, l=[1, 2, 3], s='abc', t=(1, 2, 3))
          >>> print(dut.__repr__())
          Demo(i=10, l=[1, 2, 3], s='abc', t=(1, 2, 3))
      """
      def _decorator(cls):
          def __str__(self):
              items = ["{name}={value}".format(
                  name=name,
                  value=vars(self)[name].__repr__()
              ) for name in [key for key in sorted(vars(self))]
                  if name not in get_field_mro(self.__class__, '__auto_str_ignore__')]  # pylint: disable=bad-continuation
              return "{clazz}({items})".format(
                  clazz=str(type(self).__name__),
                  items=', '.join(items)
              )
          cls.__str__ = __str__
          if __repr__:
              cls.__repr__ = __str__
  
          return cls
  
      return _decorator