gottadiveintopython · GitHub

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)ExitStack does not.

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

Furthermore, both (async) with-statement and (Async)ExitStack don'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

Read the original on github.com ↗