class SlotsCM:
__slots__ = ("__enter__", "__exit__", )
def __init__(self):
self.__enter__ = self.__exit__ = lambda *__: None
# This works
with SlotsCM():
pass
# This doesn't.
from contextllib import ExitStack
with ExitStack() as stack:
stack.enter_context(SlotsCM())
Traceback (most recent call last):
File "xxxx.py", line 16, in <module>
stack.enter_context(SlotsCM())
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
File "......../contextlib.py", line 530, in enter_context
result = _enter(cm)
TypeError: 'member_descriptor' object is not callable
Bug report
Bug description:
I noticed a behavioral difference between the (async) with statement and
(Async)ExitStack. The with statement correctly recognizes context manager methods (__enter__,__exit__,__aenter__, and__aexit__) even when they are defined via__slots__, whereas(Async)ExitStackdoes not.Furthermore, both (async) with-statement and
(Async)ExitStackdon't suppot those special dunder methods stored in__dict__. You can verify from this repository:https://github.com/gottadiveintopython/invest-context-manager
CPython versions tested on:
3.13
Operating systems tested on:
Linux
Linked PRs