def _fqdn(o, oset=True, recheck=False, pmodule=None):
    """Returns the fully qualified name of the object.

    Args:
        o (type): instance of the object's type.
        oset (bool): when True, the fqdn will also be set on the object as attribute
          `__fqdn__`.
        recheck (bool): for sub-classes, sometimes the super class has already had
          its __fqdn__ attribute set; in that case, we want to recheck the
          object's name. This usually only gets used during object extension.
    """
    if id(o) in _set_failures or o is None:
        return None
    
    if recheck or not _safe_hasattr(o, "__fqdn__"):
        import inspect
        if not hasattr(o, "__name__"):
            msg.warn("Skipped object {}: no __name__ attribute.".format(o), 3)
            return
        
        result = None
        if hasattr(o, "__acornext__") and o.__acornext__ is not None:
            otarget = o.__acornext__
        else:
            otarget = o
            
        omod = _safe_getmodule(otarget) or pmodule
        if (omod is None and hasattr(otarget, "__objclass__") and
            otarget.__objclass__ is not None): # pragma: no cover
            omod = _safe_getmodule(otarget.__objclass__)
            parts = ("<unknown>" if omod is None else omod.__name__,
                     otarget.__objclass__.__name__,
                     otarget.__name__)
            #msg.std("FQDN: objclass => {}".format(parts), 4)
            result = "{}.{}.{}".format(*parts)
        elif (omod is None and hasattr(otarget, "__class__") and
              otarget.__class__ is not None):
            omod = _safe_getmodule(otarget.__class__)
            parts = ("<unknown>" if omod is None else omod.__name__,
                     otarget.__class__.__name__,
                     otarget.__name__)
            #msg.std("FQDN: class => {}".format(parts), 4)
            result = "{}.{}.{}".format(*parts)
        elif omod is not otarget:
            parts = (_fqdn(omod, False), otarget.__name__)
            #msg.std("FQDN: o => {}".format(parts), 4)
            result = "{}.{}".format(*parts)
        else:
            result = otarget.__name__

        if oset:
            _safe_setattr(o, "__fqdn__", result)
        return result

    if _safe_hasattr(o, "__fqdn__"):
        return o.__fqdn__
Returns the fully qualified name of the object.

    Args:
        o (type): instance of the object's type.
        oset (bool): when True, the fqdn will also be set on the object as attribute
          `__fqdn__`.
        recheck (bool): for sub-classes, sometimes the super class has already had
          its __fqdn__ attribute set; in that case, we want to recheck the
          object's name. This usually only gets used during object extension.