def get_class_members(
    class_: type,
    class_api_level: str = "low",
    class_alias: Optional[str] = None,
    overrides_are_defs: bool = False,
) -> Members:
    """Get all members of a class.

    Args:
        cls: The class.

    Returns:
        Iterable of Member namedtuples.
    """

    definitions: List[Member] = []
    exports: List[Member] = []
    publics: List[Member] = []
    friends: List[Member] = []
    privates: List[Member] = []

    highs: List[Member] = []
    lows: List[Member] = []

    static_members = [
        (k, v, type(v)) for k, v in pycompat_utils.getmembers_static(class_)
    ]

    slot_members = []
    if hasattr(class_, "__slots__"):
        slot_members = [
            (name, v := getattr(class_, name), type(v))
            for name in class_.__slots__
        ]

    # Cannot get attributes of pydantic models in the above ways so we have
    # special handling for them here:
    fields_members = []
    if hasattr(class_, "model_fields") and hasattr(
        class_.model_fields, "items"
    ):  # pydantic.BaseModel (v2)
        fields_members = [
            (name, field.default, field.annotation)
            for name, field in class_.model_fields.items()
        ]
    elif (
        hasattr(class_, "__fields__")
        and hasattr(
            class_.__fields__,
            "items",  # some pydantic versions have __fields__ as a dict, some as a mappingproxy
        )
    ):  # pydantic.v1.BaseModel
        fields_members = [
            (name, field.default, field.annotation)
            for name, field in class_.__fields__.items()
        ]

    qualbase: str = (
        class_.__module__ + "." + class_.__qualname__
        if class_alias is None
        else class_alias
    )

    for name, val, typ in static_members + slot_members + fields_members:
        qualname = qualbase + "." + name
        member = Member(
            class_.__module__, name=name, qualname=qualname, val=val, typ=typ
        )

        is_def = False
        is_public = False
        is_experimental = False

        is_experimental = name.lower().startswith("experimental")

        if is_experimental:
            # Skip experimental members for now.
            # TODO: include them as another category other than public.
            continue

        if any(
            (
                (not base.__module__.startswith("trulens"))
                and hasattr(base, name)
            )
            for base in class_.__bases__
        ):
            # Skip anything that is a member of non trulens_eval bases.
            continue

        if name.startswith("__") and not name.endswith("__"):
            group = privates

        elif name.startswith("_"):
            group = friends

        else:
            is_public = True
            group = publics

        if overrides_are_defs or not any(
            (base.__module__.startswith("trulens")) and hasattr(base, name)
            for base in class_.__bases__
        ):
            # View the class-equivalent of a definitions as members of a class
            # that are not members of its bases.

            # If alias provided, we consider everything to be a definition though.
            is_def = True
            definitions.append(member)

        # There is no class-equivalent notion of exports.
        group.append(member)

        if is_public and is_def:
            if class_api_level == "high":
                highs.append(member)
            else:
                lows.append(member)

    return Members(
        obj=class_,
        version=None,
        exports=exports,
        definitions=definitions,
        access_publics=publics,
        access_friends=friends,
        access_privates=privates,
        api_highs=highs,
        api_lows=lows,
    )
Get all members of a class.

    Args:
        cls: The class.

    Returns:
        Iterable of Member namedtuples.
    
tests/utils.py