docs: def decorate_obj(parent, n, o, otype, recurse=True, redecorate=False):
      """Adds the decoration for automated logging to the specified object, if it
      hasn't already been done.
  
      Args:
          parent: object that `o` belongs to.
          n (str): name in the parent's dictionary.
          o (type): instance of the object's type.
          otype (str): one of ['classes', 'functions', 'methods', 'modules'];
            specifies which group the object belongs to.
          recurse (bool): when True, the objects methods and functions are also
            decorated recursively.
  
      Examples:
          Decorate the function `mymod.myfunc` to log automatically to the
          database.
  
      >>> from acorn.logging.decoration import decorate_obj
      >>> import mymod
      >>> decorate_obj(mymod, "myfunc", mymod.myfunc, "functions")
  
      """
      global _decor_count, _decorated_o
      from inspect import isclass, isfunction, ismodule
      pmodule = parent if ismodule(parent) or isclass(parent) else None
      fqdn = _fqdn(o, recheck=True, pmodule=pmodule)
      if fqdn is None:
          #This object didn't have a name, which means we can't extend it or
          #track it anyway.
          return
  
      package = fqdn.split('.')[0]
      d = _get_stack_depth(package, fqdn)
      if (package in _decorated_o and
          (id(o) not in _decorated_o[package] or redecorate)):
          decor = None
          if hasattr(o, "__call__") and otype != "classes":
              #calling on class types is handled by the construction decorator
              #below.
              cdecor = CallingDecorator(o)
              if isclass(parent):
                  clog = cdecor(fqdn, package, parent, d)
              else:
                  clog = cdecor(fqdn, package, None, d)
  
              #We can't update the attributes of the static methods (it just
              #produces errors), so we do what we can before that.
              msg.std("Setting decorator on {}.".format(fqdn), 4)
              _update_attrs(clog, o)
              if ((hasattr(o, "im_self") and o.im_self is parent)):
                  clog = staticmethod(clog)
              setok = _safe_setattr(parent, n, clog)
  
              if setok:
                  decor = cdecor
                  msg.okay("Set calling logger on {}: {}.".format(n, fqdn), 3)
              _decor_count[package][0] += 1
          else:
              setok = _safe_setattr(o, "__acorn__", None)
              _decor_count[package][2] += 1
  
          if otype == "classes" and setok:
              if hasattr(o, "__new__"):
                  setattr(o, "__old__", staticmethod(o.__new__))
                  crelog = creationlog(o, package, d)
                  setok = _safe_setattr(o, "__new__", creationlog(o, package, d))
                  
                  if setok:
                      decor = crelog
                      msg.gen("Set creation logger on {}: {}.".format(n, fqdn),3)
                  _decor_count[package][0] += 1
              #else: must have only static methods and no instances.
              
          if setok:
              _decorated_o[package][id(o)] = decor
          else:
              _decorated_o[package][id(o)] = None
  
          #We don't need to bother recursing for those modules/classes that
          #can't have their attributes set, since their members will have the
          #same restrictions.
          if setok and otype in ["classes", "modules"]:
              #These types can be further decorated; let's traverse their members
              #and try to decorate those as well.
              splits = _split_object(o, package)
              for ot, ol in splits.items():
                  for nobj, obj in ol:
                      decorate_obj(o, nobj, obj, ot)
              
      elif otype != "classes" and package in _decorated_o:
          #Even though the object with that id() has been decorated, it doesn't
          #mean that the parent has had its attribute overwritten to point to the
          #decorated object. This happens with instance methods on different
          #classes that are implemented by another generic method.
          target = _decorated_o[package][id(o)]
          child = getattr(parent, n)
          if target is not None:
              clog = target(fqdn, package, parent)
              _safe_setattr(clog, "__acorn__", o)
              _update_attrs(clog, o)
              
              setok = _safe_setattr(parent, n, clog)
              msg.okay("Set existing calling logger on {}: {}.".format(n,fqdn), 4)