Pylance ругается на вызов Union аргумента функции

Рейтинг: 0Ответов: 1Опубликовано: 28.06.2023

У меня есть следующий код как минимально воспроизводимый пример:

from typing import Any, Callable, Generic, Optional, TypeVar, Union
from random import choice

T1 = TypeVar("T1")

class qux(Generic[T1]):
    def foo(self) -> Callable[[T1], None]:
        def foo_wrapper(arg:T1):
            print(f'Foo wrapper called with argument {arg}')

        return foo_wrapper

    def bar(self) -> Callable[[], None]:
        def bar_wrapper():
            print('Bar wrapper called without arguments')
        
        return bar_wrapper
        
    def buzz(self, func:Union[Callable[[T1], Any], Callable[[], Any]], arg: Optional[T1] = None):
        if arg:
            func(arg)
        else:
            func()
            
    def choice_impl(self, flag:bool):
        if flag:
            return self.foo()
        else:
            return self.bar()
    
qux_instance = qux()
value = None
if choice((True, False)):
    value = 42

flag = value is not None

implementation = qux_instance.choice_impl(flag=flag)
if flag:
    qux_instance.buzz(func=implementation, arg=value)
else:
    qux_instance.buzz(func=implementation)

Pylance ругается на строку 21:

Expected 0 positional arguments  (parameter) arg: T1@qux

и 23:

Expected 1 more positional argument (parameter) func: ((T1@qux) -> Any) | (() -> Any)

потому что он не знает, какая сигнатура у аргумента func функции buzz будет на момент вызова. Хотя этот код всегда выполняется без ошибок. Как мне решить эту проблему? Это баг Pylance или это связанно с проблемой останова? Или это у меня руки кривые?

Ответы

▲ 2Принят

В данном случае можно использовать cast из модуля typing:

    def buzz(self, func:Union[Callable[[T1], Any], Callable[[], Any]], arg: Optional[T1] = None):
        if arg:
            cast(Callable[[T1], Any], func)(arg)
        else:
            cast(Callable[[], Any], func)()

Но это по сути отключает защиту, статический анализатор никак не сможет проверить соответствие, что вы передали функцию с одним аргументом и аргумент для нее или функцию без аргументов, и не передали аргумент.