Add an else clause to with statements to detect early termination

I think the problem with that is that the enter_context() calls are dynamic. If the underlying context managers were present in the ExitStack constructor, you could probably do this with typevars. But here we’re calling cm.enter_context(subcm), and we’d want those calls to affect the type of cm. That makes me think of how (in mypy, at least) we have a special case for

xs = []
for ...:
    x = ...
    xs.append(x)

where the inferred type for x will affect the type inferred for xs – this is hard, and except for the very simplest cases we require you to provide the answer by starting with

xs: list[SomeType] = []

so that the type of x is checked against SomeType instead of changing it.

If the answer was dependent types, since we don’t have those, we’d end up needing my proposed solution anyway.

Also, the enter_context() calls might occur inside some other thing that is called, e.g.

with ExitStack() as cm:
    foo(cm)

where foo() is something like this:

def foo(cm: ExitStack):
    cm.enter_context(...)

Well, maybe this could be solved by making ExitStack generic:

class ExitStack[T: bool|None]:
    ...
    def __exit__(self, ...) -> T: ...

If this could work we’d be able to say

type NonSuppressingExitStack = ExitStack[None]
2 Likes