# With statements ## Basic `with` statement The type of the target variable in a `with` statement is the return type from the context manager's `__enter__` method. ```py class Target: ... class Manager: def __enter__(self) -> Target: return Target() def __exit__(self, exc_type, exc_value, traceback): ... with Manager() as f: reveal_type(f) # revealed: Target ``` ## Union context manager ```py def _(flag: bool): class Manager1: def __enter__(self) -> str: return "foo" def __exit__(self, exc_type, exc_value, traceback): ... class Manager2: def __enter__(self) -> int: return 42 def __exit__(self, exc_type, exc_value, traceback): ... context_expr = Manager1() if flag else Manager2() with context_expr as f: reveal_type(f) # revealed: str | int ``` ## Context manager without an `__enter__` or `__exit__` method ```py class Manager: ... # error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because it does not implement `__enter__` and `__exit__`" with Manager(): ... ``` ## Context manager without an `__enter__` method ```py class Manager: def __exit__(self, exc_tpe, exc_value, traceback): ... # error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because it does not implement `__enter__`" with Manager(): ... ``` ## Context manager without an `__exit__` method ```py class Manager: def __enter__(self): ... # error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because it does not implement `__exit__`" with Manager(): ... ``` ## Context manager with non-callable `__enter__` attribute ```py class Manager: __enter__: int = 42 def __exit__(self, exc_tpe, exc_value, traceback): ... # error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because it does not correctly implement `__enter__`" with Manager(): ... ``` ## Context manager with non-callable `__exit__` attribute ```py from typing_extensions import Self class Manager: def __enter__(self) -> Self: return self __exit__: int = 32 # error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because it does not correctly implement `__exit__`" with Manager(): ... ``` ## Context expression with possibly-unbound union variants ```py def _(flag: bool): class Manager1: def __enter__(self) -> str: return "foo" def __exit__(self, exc_type, exc_value, traceback): ... class NotAContextManager: ... context_expr = Manager1() if flag else NotAContextManager() # error: [invalid-context-manager] "Object of type `Manager1 | NotAContextManager` cannot be used with `with` because the methods `__enter__` and `__exit__` are possibly unbound" with context_expr as f: reveal_type(f) # revealed: str ``` ## Context expression with "sometimes" callable `__enter__` method ```py def _(flag: bool): class Manager: if flag: def __enter__(self) -> str: return "abcd" def __exit__(self, *args): ... # error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because the method `__enter__` is possibly unbound" with Manager() as f: reveal_type(f) # revealed: str ``` ## Invalid `__enter__` signature ```py class Manager: def __enter__() -> str: return "foo" def __exit__(self, exc_type, exc_value, traceback): ... context_expr = Manager() # error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because it does not correctly implement `__enter__`" with context_expr as f: reveal_type(f) # revealed: str ```