diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index 4ea50e5eb34c..dff34474d2f5 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -178,9 +178,15 @@ class _BaseExitStack(Generic[_ExitT_co]): def callback(self, callback: Callable[_P, _T], /, *args: _P.args, **kwds: _P.kwargs) -> Callable[_P, _T]: ... def pop_all(self) -> Self: ... -# In reality this is a subclass of `AbstractContextManager`; -# see #7961 for why we don't do that in the stub -class ExitStack(_BaseExitStack[_ExitT_co], metaclass=abc.ABCMeta): +# this class is to avoid putting `metaclass=abc.ABCMeta` on the implementations directly, as this would make them +# appear explicitly abstract to some tools. this is due to the implementations not subclassing `AbstractContextManager` +# see note on the subclasses +@type_check_only +class _BaseExitStackAbstract(_BaseExitStack[_ExitT_co], metaclass=abc.ABCMeta): ... + +# In reality this is a subclass of `AbstractContextManager`, but we can't provide `Self` as the argument for `__enter__` +# https://discuss.python.org/t/self-as-typevar-default/90939 +class ExitStack(_BaseExitStackAbstract[_ExitT_co]): def close(self) -> None: ... def __enter__(self) -> Self: ... def __exit__( @@ -192,9 +198,9 @@ _ExitCoroFunc: TypeAlias = Callable[ ] _ACM_EF = TypeVar("_ACM_EF", bound=AbstractAsyncContextManager[Any, Any] | _ExitCoroFunc) -# In reality this is a subclass of `AbstractAsyncContextManager`; -# see #7961 for why we don't do that in the stub -class AsyncExitStack(_BaseExitStack[_ExitT_co], metaclass=abc.ABCMeta): +# In reality this is a subclass of `AbstractContextManager`, but we can't provide `Self` as the argument for `__enter__` +# https://discuss.python.org/t/self-as-typevar-default/90939 +class AsyncExitStack(_BaseExitStackAbstract[_ExitT_co]): async def enter_async_context(self, cm: AbstractAsyncContextManager[_T, _ExitT_co]) -> _T: ... def push_async_exit(self, exit: _ACM_EF) -> _ACM_EF: ... def push_async_callback(