Skip to content

Narrow x is Sentinel where x is Union[type[Sentinel], ...] and Sentinel is @final #15553

Open
coderabbit-test/mypy
#6
@jonathanslenders

Description

@jonathanslenders

Feature

Apply type narrowing in case of x is not C where x is of type Union[type[C], SomethingElse], from that union to SomethingElse in case when C is made final.

If C is final, then C is the only possible value that satisfies the type type[C]. So, if we compare identity, that means we can narrow the type in either direction.

Pitch

Empty class definitions are often used as sentinel values in a union, together with something else. These sentinel values can be made @final.

Consider this code:

from typing import final, Union, Literal

@final
class Sentinel:
    pass

x: Union[type[Sentinel], int]

if x is Sentinel:
    pass
else:
    # Should be `int`
    # But is: "Union[Type[x.Sentinel], builtins.int]"
    reveal_type(x)

An example can be found in the h11 library:
https://github.com/python-hyper/h11/blob/cdccbeff44a39426b58010eb454a75015ec6f8bc/h11/_connection.py#L426

    def next_event(self) -> Union[Event, Type[NEED_DATA], Type[PAUSED]]:

Many libraries are doing that. A workaround that currently works is to use instantiated objects instead of types for sentinel values and narrow them by using an isinstance() check on the sentinel type, but that's far less clean, because for every sentinel we now have to deal with both the class and the instance.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions