Search code examples
pythonclass-methodcontextmanager

How to use contextlib.contextmanager with a classmethod?


See the below Python 3.10 snippet:

import contextlib

class Foo:
    @contextlib.contextmanager
    @classmethod
    def state(cls):
        try:
            yield
        finally:
            pass

with Foo.state():
    pass

It throws a TypeError:

Traceback (most recent call last):
  File "/path/to/code/play/quick_play.py", line 12, in <module>
    with Foo.state():
  File "/path/to/.pyenv/versions/3.10.5/lib/python3.10/contextlib.py", line 281, in helper
    return _GeneratorContextManager(func, args, kwds)
  File "/path/to/.pyenv/versions/3.10.5/lib/python3.10/contextlib.py", line 103, in __init__
    self.gen = func(*args, **kwds)
TypeError: 'classmethod' object is not callable

Is it possible to decorate a classmethod with contextlib.contextmanager? And if yes, how can it be done?


Solution

  • This should work:

    import contextlib
    
    class Foo:
        @classmethod
        @contextlib.contextmanager
        def state(cls):
            try:
                print("A")
                yield
                print("C")
            finally:
                pass
    
    with Foo.state():
        print("B")
    

    This prints A B C.