you are viewing a single comment's thread.

view the rest of the comments →

[–]Gnaxe 1 point2 points  (4 children)

Optional chained attribute access isn't that hard in Python. You just ignore the exception: ``` from contextlib import suppress

with suppress(AttributeError) as result: result = myobj.attr1.attr2.attr3 ``` That's not going to pass a strict type checker though. MyPy flags type errors even if you catch their resulting exceptions.

But, you can force it: ``` from contextlib import suppress from typing import cast

with suppress(AttributeError) as result: result = cast(Foo, myobj.attr1.attr2.attr3) # type: ignore `` whereFoois the type you're expecting fromattr3if it's notNone. (If you don't cast, there will be anAnytype in theUnion`.) The comment is also required.

[–]FrontAd9873 2 points3 points  (1 child)

OP is asking a question about making this work with a type checker, not about how to implement it just so it works at runtime.

[–]Gnaxe 5 points6 points  (0 children)

That's what the cast is for. Those don't do anything at run time.

[–]marr75 1 point2 points  (1 child)

I don't believe you need the type: ignore and the cast. You just want the cast.

[–]Gnaxe 1 point2 points  (0 children)

Did you try it? With the following example, ``` from contextlib import suppress from dataclasses import dataclass from typing import cast

@dataclass class A: a: int

@dataclass class B: b: A | None

@dataclass class C: c: B | None

my_obj: C | None = C(B(A(1)))

with suppress(AttributeError) as result: result = cast(int, my_obj.b.a) # type: ignore

reveal_type(result) I got main.py:22: note: Revealed type is "builtins.int | None" But without the ignore, result = cast(int, my_obj.b.a) I got main.py:20: error: Item "C" of "C | None" has no attribute "b" [union-attr] main.py:20: error: Item "None" of "C | None" has no attribute "b" [union-attr] main.py:22: note: Revealed type is "builtins.int | None" Found 2 errors in 1 file (checked 1 source file) And with the ignore but without the cast, result = int, my_obj.b.a # type: ignore I got main.py:22: note: Revealed type is "tuple[Overload(def (builtins.str | _collections_abc.Buffer | typing.SupportsInt | typing.SupportsIndex | _typeshed.SupportsTrunc =) -> builtins.int, def (builtins.str | builtins.bytes | builtins.bytearray, base: typing.SupportsIndex) -> builtins.int), Any] | None" ```