Skip to content

API Reference

class_singledispatch.

A singledispatch for arguments that are classes annotated as specific types.

https://github.com/python/cpython/issues/100623

resolve_annotated_type(func: Callable[..., _R]) -> type[Any]

Resolve the annotated type of the first argument of func.

This function is used to determine the type of the first argument of func when the first argument is annotated as a type (e.g. type[SomeClass]).

Source code in class_singledispatch/__init__.py
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
def resolve_annotated_type(func: Callable[..., _R]) -> type[Any]:
    """
    Resolve the annotated type of the first argument of `func`.

    This function is used to determine the type of the first argument of `func`
    when the first argument is annotated as a type (e.g. `type[SomeClass]`).
    """
    func_annotations = getattr(func, "__annotations__", {})
    if not func_annotations:
        msg = (
            f"Invalid first argument to `register()`: {func!r}. "
            f"Use either `@register(some_class)` or plain `@register` "
            f"on an annotated function."
        )
        raise TypeError(msg)
    for key, value in func_annotations.items():
        if isinstance(value, str):
            func_annotations[key] = ForwardRef(value)
    argument_name, generic_alias = next(iter(get_type_hints(func).items()))
    if not (
        isinstance(generic_alias, (GenericAlias, OldFashionGenericAlias))
        and ((origin := get_origin(generic_alias)) is Type or isinstance(origin, type))
    ):
        msg = (
            f"Invalid annotation for {argument_name!r}. "
            f"{generic_alias!r} is not an annotation of type (e.g. type[T])."
        )
        raise TypeError(msg)
    cls = next(iter(get_args(generic_alias)), object)
    if not isinstance(cls, type):
        msg = (
            f"Invalid annotation for {argument_name!r}. {cls!r} is not a runtime class."
        )
        raise TypeError(msg)
    return cls

class_singledispatch(func: Callable[..., _R]) -> _ClassSingleDispatchCallable[_R]

Use functools.singledispatch to dispatch classes as parameters.

While singledispatch examines the class of the first user argument, class_singledispatch uses the first argument as the class itself and performs the same task with it as singledispatch.

class T:
    pass

class OtherT:
    pass

@class_singledispatch
def on_class(cls: type[T], /) -> None:
    print("T!")

@on_class.register
def on_other_class(cls: type[OtherT], /) -> None:
    print("OtherT!")

# Useful for <3.10 without eval_type_backport:
# Pass the class to the decorator not to use the annotation for resolution
@on_class.register(SomeOtherT)
def on_some_other_class(cls: type[SomeOtherT], /) -> None:
    print("SomeOtherT!")

on_class(T)  # T!
on_class(OtherT)  #  OtherT!
on_class(SomeOtherT)  #  SomeOtherT!
Source code in class_singledispatch/__init__.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
def class_singledispatch(
    func: Callable[..., _R],
    /,
) -> _ClassSingleDispatchCallable[_R]:
    """
    Use [`functools.singledispatch`][functools.singledispatch] to dispatch
    classes as parameters.

    While `singledispatch` examines the class of the first user argument,
    [`class_singledispatch`][class_singledispatch.class_singledispatch] uses
    the first argument as the class itself and performs the same task with it
    as `singledispatch`.

    ```python
    class T:
        pass

    class OtherT:
        pass

    @class_singledispatch
    def on_class(cls: type[T], /) -> None:
        print("T!")

    @on_class.register
    def on_other_class(cls: type[OtherT], /) -> None:
        print("OtherT!")

    # Useful for <3.10 without eval_type_backport:
    # Pass the class to the decorator not to use the annotation for resolution
    @on_class.register(SomeOtherT)
    def on_some_other_class(cls: type[SomeOtherT], /) -> None:
        print("SomeOtherT!")

    on_class(T)  # T!
    on_class(OtherT)  #  OtherT!
    on_class(SomeOtherT)  #  SomeOtherT!
    ```
    """  # noqa: D205
    return _ClassSingleDispatchCallable(func)