Cameron Hurst
Cameron Hurst

Reputation: 273

How to specify type based on runtime condition

I am using mypy and protocols and have run into a spot where I would like type hinting if possible, but I am unable to figure out how I should set it up so mypy doesn't error.

Consider the following example:

class TProtocol(Protocol):
    t: str

@attrs(auto_attribs=True)
class T:
    t: str
    t2: str

@attrs(auto_attribs=True)
class T2:
    t: str

def func(var: TProtocol) -> None:
    if some_condition:
        var: T
        reveal_type(var)
    else:
        reveal_type(var)

While very contrived, it illustrates my goal of I have some runtime condition that if met I know that the type of that variable based on knowledge of the code base. I then want to pass this knowledge onto mypy so that further type checking uses that type.

The same example can be replace with a Union. Some runtime check occurs which tells me explicitly which one of the types I have based on knowledge of the code base. I then want to tell mypy explicitly which type that is for further type checking based on that outside knowledge.

The above example raises an error stating that var is already defined. I tried the allow_redefinition option and it didn't change the output.

Upvotes: 4

Views: 1147

Answers (1)

MisterMiyagi
MisterMiyagi

Reputation: 50076

Use typing.cast to forcefully declare a variable as a specific type. This disregards any other typing information, and works on runtime-branches as well.

def func(var: TProtocol) -> None:
    reveal_type(var)         # line 21
    if some_condition:
        var = cast(T, var)   # line 23
        reveal_type(var)
    else:
        var = cast(T2, var)  # line 26
        reveal_type(var)

This makes mypy treat each casted occurrence of var differently, i.e. before and inside each branch:

type_tests.py:21: note: Revealed type is 'type_tests.TProtocol'
type_tests.py:24: note: Revealed type is 'type_tests.T'
type_tests.py:27: note: Revealed type is 'type_tests.T2'

Upvotes: 2

Related Questions