Splits the specified object into its modules, classes, methods and
    functions so that it can be decorated more easily. For extension
    modules/classes that can't have attributes set, the object's dictionary is
    modified to point to a derived-type version.

    Args:
        pobj: object instance returned from the import.
        package (str): name of the package (used for filtering all the loaded
          packages and methods inside the package object).
        resplit (bool): if True, re-processes the object, even if has been done
          before.
        packincl (list): of package names that should be considered relevant when
          deciding how to filter the members of this object. If a member belongs
          to one of these packages, they will be included in the split for the
          object.
        skipext (bool): when True, the list of split objects is only returned;
          no attempts are made to extend any objects for decoration.

def _split_object(pobj, package, resplit=False, packincl=None, skipext=False):
    """Splits the specified object into its modules, classes, methods and
    functions so that it can be decorated more easily. For extension
    modules/classes that can't have attributes set, the object's dictionary is
    modified to point to a derived-type version.

    Args:
        pobj: object instance returned from the import.
        package (str): name of the package (used for filtering all the loaded
          packages and methods inside the package object).
        resplit (bool): if True, re-processes the object, even if has been done
          before.
        packincl (list): of package names that should be considered relevant when
          deciding how to filter the members of this object. If a member belongs
          to one of these packages, they will be included in the split for the
          object.
        skipext (bool): when True, the list of split objects is only returned;
          no attempts are made to extend any objects for decoration.
    """
    import inspect
    result = {
        "classes": [],
        "functions": [],
        "methods": [],
        "modules": [],
        "builtins": [],
        "descriptors": [],
        "unknowns": []
        }

    global _split_objects
    if pobj in _split_objects and not resplit:
        return result
    
    tests = {
        "classes": inspect.isclass,
        "functions": inspect.isfunction,
        "methods": inspect.ismethod,
        "modules": inspect.ismodule,
        "builtins": inspect.isbuiltin,
        "descriptors": inspect.ismethoddescriptor
        }

    from functools import partial
    prepack = "{}.".format(package)
    pms = []
    pmodule = pobj if inspect.ismodule(pobj) or inspect.isclass(pobj) else None
    for n, o in _get_members(pobj):
        if isinstance(o, (dict, list, set, float, int, str, complex, bool)):
            #We are looking for functions, modules and packages; sometimes
            #constants are declared that we just ignore.
            continue
        else:
            omod = _safe_getmodule(o)
            if omod is None:
                #This may be an instance method of an object-class. In that
                #case, we still want to decorate it.
                if hasattr(o,"__objclass__") and o.__objclass__ is not type:
                    omod = _safe_getmodule(o.__objclass__)
                elif hasattr(o, "__class__") and o.__class__ is not type:
                    omod = _safe_getmodule(o.__class__)
                else:
                    omod = pmodule

                #Catch the last outlier case: C-extension built-in descriptors
                #methods for "built-in" objects.
                if omod is None and inspect.ismethoddescriptor(o):
                    omod = pmodule
                    
        #Some packages define special types with __class__ = type. These are
        #indistinguishable from the built-in types like `float` or `str`. So we
        #force the developers to configure these manually.
        packok = False
        confok = False
        pincl = False        
        if omod is not None:
            if packincl is not None and len(packincl) > 0:
                #We want to sometimes return all the objects available at the
                #top-level of a package, even if they were imported from a
                #different package. This doesn't get called in normal decoration
                #mode, except for certain special packages.
                fqdn_ = _fqdn(o, False, pmodule=pmodule)
                if fqdn_ is not None:
                    pincl = any(p in fqdn_ for p in packincl)

            omodname = (omod.__name__ if inspect.ismodule(omod)
                        else _fqdn(omod, False))
            packok = (prepack in omodname or omodname == package or pincl)
            if not packok and hasattr(o, "__class__") and o.__class__ is type:
                fqdn_ = _fqdn(o, False, pmodule=pmodule)
                incl = filter_name(fqdn_, package, explicit=True)
                if incl: # pragma: no cover
                    filesrc = inspect.getabsfile(pobj)
                    confok = "/{}/".format(package) in filesrc
                
        if packok or confok:
            pms.append((n, o, confok))                    

    global _decor_count
    def oappend(n, o, t, result, confok):
        """Appends the specified object to `results` if it can be extended.

        Args:
            confok (bool): when True, the code has already determined previously
              that this object should be decorated no matter what (the user said
              so). In that case, we bypass the regular name checks.
        """
        fqdn = _fqdn(o, False, pmodule=pmodule)
        if fqdn is None:
            #The object was probably of type unknown and doesn't have a __name__
            #attribute, so we just skip it.
            return

        package = fqdn.split('.')[0]
        if confok or (filter_name(n, package) and filter_name(fqdn, package)):
            xobj = _extend_object(pobj, n, o, t, fqdn)
            if xobj is not None:
                result[t].append((n, xobj))
            else: # pragma: no cover
                msg.warn("Couldn't extend {} ({}).".format(o, t), 2)
        else:
            skipmsg = "Skipping {}: {} because of filter rules."
            msg.info(skipmsg.format(n, fqdn), 4)
            if package in _decor_count:
                _decor_count[package][1] += 1
        
    for n, o, confok in pms:
        for t, f in tests.items():
            if f(o):
                if skipext:
                    result[t].append((n, o))
                else:
                    oappend(n, o, t, result, confok)
                break
        else:
            #With some class instances (which end up being members of
            #objects), an error is raised because they implement their own
            #__getattr__ routine that wasn't designed to work with acorn. We
            #just ignore these. We don't want to decorate object instances
            #anyway, except that numpy.ufunc instances are actually
            #functions that don't match any of the inspect.is* methods, and
            #so we have this catch-all over here.
            cancall = _safe_hasattr(o, "__call__")
            if cancall:
                if skipext: # pragma: no cover
                    result["unknowns"].append((n, o))
                else:
                    oappend(n, o, "unknowns", result, confok)

    _split_objects.append(pobj)
    return result