Python 类型检查:Literal[False]、重载和 NoReturn

Python type-checking: Literal[False], overload, and NoReturn

我有以下(键入的)Python 函数:

from typing import overload, Literal, NoReturn

@overload
def check(condition: Literal[False], msg: str) -> NoReturn:
    pass

@overload
def check(condition: Literal[True], msg: str) -> None:
    pass

def check(condition, msg):
    if not condition:
        raise Exception(msg)

Pyright 类型检查器抱怨:

Overloaded function implementation is not consistent with signature of overload 1
  Function return type "NoReturn" is incompatible with type "None"
    Type cannot be assigned to type "None"

我对此感到困惑——Pyright 显然无法确定如果条件为 Falsecheck 将始终抛出错误。我怎样才能按摩它使其发挥作用?

我将此发布到 Pyright 问题跟踪器并且 informed 我必须向 check 实现添加 Union[NoReturn, None] 注释以解决错误:

[This] falls out of pyright's rules for return type inference. Pyright will infer a NoReturn type only in the case that all code paths raise an exception. It's quite common for some code paths raise an exception, and it would produce many false positives if pyright were to include NoReturn in the union in that case, so NoReturn is always elided from a union in an inferred return type.

Mypy doesn't have any support for return type inference, so that explains why this doesn't occur for mypy.

The correct way to annotate this is to include an explicit None | NoReturn return type for the implementation.

不幸的是,这首先违背了重载的目的,即当 NoReturn 是 return 类型时,允许 PyRight 从参数中推断出来。我问是否可以使用 overloads 有条件地向类型检查器表达 NoReturn 。显然 it is not:

Unfortunately, pyright cannot make this determination because of its core architecture. The "reachability" of nodes within a code flow graph cannot rely on type evaluations because type evaluations depend on reachability of code flow nodes. To work around this chicken-and-egg problem, the logic that determines reachability does some basic checks to determine if the called function is potentially a "NoReturn" function, but these basic checks are not sophisticated enough to handle overload evaluation. Evaluating overloads requires the full type evaluator, and that depends on reachability.