How can I mix decorators with the @contextmanager decorator?

Here is the code I'm working with:

from contextlib import contextmanager
from functools import wraps
class with_report_status(object):

    def __init__(self, message):
        self.message = message

    def __call__(self, f):
        @wraps(f)
        def wrapper(_self, *a, **kw):
            try:
                return f(_self, *a, **kw)
            except:
                log.exception("Handling exception in reporting operation")
                if not (hasattr(_self, 'report_status') and _self.report_status):
                    _self.report_status = self.message
                raise

        return wrapper

class MyClass(object):

    @contextmanager
    @with_report_status('unable to create export workspace')
    def make_workspace(self):
        temp_dir = tempfile.mkdtemp()
        log.debug("Creating working directory in %s", temp_dir)
        self.workspace = temp_dir
        yield self.workspace
        log.debug("Cleaning up working directory in %s", temp_dir)
        shutil.rmtree(temp_dir)

    @with_report_status('working on step 1')
    def step_one(self):
        # do something that isn't a context manager

The problem is that it @with_report_statusdoes not, as expected @contextmanager. However, I cannot wrap it in another way, because it @contextmanagerreturns a generator object (I think!) Instead of the value itself.

How can I make @contextmanagerfun with decorators?

+3
source share
2 answers

This is kind of a weird question: the @contextmanagercontext manager returns, not the generator. But for some reason, do you want to consider this context manager as a function? This is not something you can do, they have nothing in common.

, MyClass.make_workspace, , report_status . , __exit__, @contextmanager .

contextlib.GeneratorContextManager, . , , .

+1

@contextmanager .

0

Source: https://habr.com/ru/post/1786309/


All Articles