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")

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)