Erlend Magnus Viggen
Erlend Magnus Viggen

Reputation: 383

Is there a shorter way to tell Mypy that a given optional chaining is fine?

I am working on Python code where the domain logic makes it natural to have a class with an optional field of a second class, which itself has an optional field of a third class. Boiling it down to a minimum working example, this is what I mean:

class C:
    def __init__(self, number: int) -> None:
        self.number = number

class B:
    def __init__(self, c: C | None) -> None:
        self.c = c

class A:
    def __init__(self, b: B | None) -> None:
        self.b = b

At some point in our code, we are receiving an object a of class A where we know that the field a.b is not None and furthermore that that the nested field a.b.c is not None. Of course, mypy does not know this and sensibly informs us that we might be doing something stupid:

# Here is an object where it is guaranteed that we won't encounter None values
a = A( B( C(1337) ) )

print(a.b.c.number)   # mypy sensibly returns two errors:
                      # Item "None" of "B | None" has no attribute "c"
                      # Item "None" of "C | Any | None" has no attribute "number"

# This satisfies mypy:
assert (a.b is not None) and (a.b.c is not None)
print(a.b.c.number)   

This assert statement works perfectly well, but it looks cumbersome when our fields names are longer and the nesting goes deeper. Is there a neater and shorter way to satisfy mypy?

Upvotes: 0

Views: 111

Answers (0)

Related Questions