import inspect


def find_all_subclasses(parent_cls, discard_abstract=False, include_parent=True):
    """Return a set of all the classes inheriting from ``parent_cls``.

    The functions handle multiple inheritance and discard the same classes.

    Parameters
    ----------
    parent_cls : type
        The parent class.
    discard_abstract : bool, optional
        If True, abstract classes are not returned (default is False).
    include_parent : bool, optional
        If True, the parent class will be included, unless it is abstract
        and ``discard_abstract`` is ``True``.

    Returns
    -------
    subclasses : set of type
        The set of all the classes inheriting from ``parent_cls``.

    """
    subclasses = set()
    for subcls in parent_cls.__subclasses__():
        if not (discard_abstract and inspect.isabstract(subcls)):
            subclasses.add(subcls)
        subclasses.update(find_all_subclasses(subcls, discard_abstract))

    if include_parent and not inspect.isabstract(parent_cls):
        subclasses.add(parent_cls)
    return subclasses