Input-Dependent Generics in Python
In PTB, we have the class CallbackContext
, which is integral in the framework and we want to allow users to customize it by subclassing and passing the subclass to the Updater/Dispatcher
. Now type hinting becomes a little bit more difficult, because we need to make sure that the callbacks
have the annotation Callable[Update, CallbackContext]
or Callable[Update, UsersCallbackContext]
and of course we would like to make that dependent on the users input. (For the full details see ptb/#2068)
First, we think of Generics
, i.e. we make Dispatcher
a generic class and use the generic type T
in the annotations like callback: Callable[Update, T]
. This works fine, but it still requires the user to tell the type checker, what T
is, i.e. with
dispatcher = Dispatcher(..., custom_type = UsersCallbackContext)
MyPy will ask the user to specify the dispatchers type as follows:
dispatcher: Dispatcher[UsersCallbackContext] = Dispatcher(..., custom_context = UsersCallbackContext)
That's unnecessary repetition. Also, we would like to have T
fall back to CallbackContext
, if the user doesn't provide a custom class.
After poking around a bit, I came across a solution in this thread. The idea is to overload the self
argument in the __init__
method as follows:
@overload
def __init__(self: Dispatcher[CallbackContext], *args): # not listing optional arguments!
...
@overload
def __init__(self: Dispatcher[T], ..., custom_context: Type[T]):
...
This works like a charm :)