Skip to content

c108.utils

C108 Utilities and compatibility shims shared across the package.

Contains functions used by multiple modules to avoid circular imports.

class_name(obj, fully_qualified=False, fully_qualified_builtins=False, as_instance=False)

Get the class name of an object or a class.

Returns class name whether given an instance or the class itself. For example, both class_name(10) and class_name(int) return 'int'.

This function safely handles edge cases including objects without standard attributes (class, name, module) by falling back to str() representation. Special handling for typing module constructs returns readable representations like 'List[int]' or 'Union[int, str]'.

Parameters:

Name Type Description Default
obj Any

An object or a class.

required
fully_qualified bool

If true, returns the fully qualified name for user objects or classes.

False
fully_qualified_builtins bool

If true, returns the fully qualified name for builtin objects or classes.

False
as_instance bool

If True, class objects are treated as regular instances, returning their metaclass name (usually 'type'). If False (default), class objects return their own name.

False

Returns:

Name Type Description
str str

The class name, or a string representation if standard attributes are unavailable.

Examples:

Basic usage with a builtin instance: >>> class_name(10) 'int'

Fully qualified name for a builtin (when enabled): >>> class_name(10, fully_qualified_builtins=True) 'builtins.int'

User-defined class: instance and class object: >>> class C: ... >>> class_name(C()) 'C' >>> class_name(C, fully_qualified=True) 'c108.utils.C'

Treating classes as instances: >>> class_name(int) 'int' >>> class_name(int, as_instance=True) 'type'

Typing constructs with readable representations: >>> from typing import List, Union >>> class_name(List[int]) 'List[int]' >>> class_name(Union[int, str]) 'Union[int, str]'

Source code in c108/utils.py
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
def class_name(
    obj: Any,
    fully_qualified: bool = False,
    fully_qualified_builtins: bool = False,
    as_instance: bool = False,
) -> str:
    """
    Get the class name of an object or a class.

    Returns class name whether given an instance or the class itself.
    For example, both `class_name(10)` and `class_name(int)` return 'int'.

    This function safely handles edge cases including objects without standard
    attributes (__class__, __name__, __module__) by falling back to str()
    representation. Special handling for typing module constructs returns
    readable representations like 'List[int]' or 'Union[int, str]'.

    Parameters:
        obj (Any): An object or a class.
        fully_qualified (bool): If true, returns the fully qualified name for user objects or classes.
        fully_qualified_builtins (bool): If true, returns the fully qualified name for builtin objects or classes.
        as_instance (bool): If True, class objects are treated as regular instances,
                            returning their metaclass name (usually 'type').
                            If False (default), class objects return their own name.

    Returns:
        str: The class name, or a string representation if standard attributes are unavailable.

    Examples:
        Basic usage with a builtin instance:
            >>> class_name(10)
            'int'

        Fully qualified name for a builtin (when enabled):
            >>> class_name(10, fully_qualified_builtins=True)
            'builtins.int'

        User-defined class: instance and class object:
            >>> class C: ...
            >>> class_name(C())
            'C'
            >>> class_name(C, fully_qualified=True)
            'c108.utils.C'

        Treating classes as instances:
            >>> class_name(int)
            'int'
            >>> class_name(int, as_instance=True)
            'type'

        Typing constructs with readable representations:
            >>> from typing import List, Union
            >>> class_name(List[int])
            'List[int]'
            >>> class_name(Union[int, str])
            'Union[int, str]'
    """
    # Determine whether to inspect the object itself or its class
    if isinstance(obj, type) and not as_instance:
        # obj is a class, and we want the class's own name
        cls = obj
    else:
        # obj is an instance, or we're treating a class as an instance
        try:
            cls = obj.__class__
        except AttributeError:
            # Fallback for objects without __class__
            return str(obj)

    # Get the class name safely
    try:
        name = cls.__name__
    except AttributeError:
        # Fallback for types without __name__
        # Extract clean name from repr() if it matches pattern "<class 'Foo'>"
        repr_str = str(cls)
        if repr_str.startswith("<class '") and repr_str.endswith("'>"):
            # Extract just the class name part, e.g., "module.ClassName"
            return repr_str[8:-2]
        # Otherwise return the full repr without angle brackets
        return repr_str.strip("<>")

    # Get the module safely
    try:
        module = cls.__module__
    except AttributeError:
        # No module info available, just return the name
        return name

    # Special handling for typing module constructs
    if module == "typing":
        # These are typing constructs with internal names like _GenericAlias
        str_repr = str(obj)
        # Strip all 'typing.' prefixes for cleaner output
        str_repr = str_repr.replace("typing.", "")
        return str_repr

    # If class is builtin
    if module == "builtins":
        if fully_qualified_builtins:
            return f"{module}.{name}"
        else:
            return name
    else:
        if fully_qualified:
            return f"{module}.{name}"
        else:
            return name