Как я могу смешать декораторы с декоратором @contextmanager? - PullRequest
3 голосов
/ 19 января 2011

Вот код, с которым я работаю:

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

Проблема в том, что @with_report_status не дает, как ожидалось @contextmanager.Однако я не могу обернуть его и наоборот, потому что @contextmanager возвращает объект-генератор (я думаю!) Вместо самого значения.

Как я могу заставить @contextmanager играть с декораторами

Ответы [ 2 ]

1 голос
/ 19 января 2011

Это довольно странный вопрос: @contextmanager возвращает менеджер контекста, а не генератор.Но по какой-то причине вы хотите рассматривать этот менеджер контекста как функцию?Это не то, что вы можете заставить работать, они не имеют ничего общего.

Я думаю, что вы хотите MyClass.make_workspace, который является менеджером контекста и также имеет поле report_status в случае исключений.Для этого вам нужно написать менеджер контекста, который устанавливает это поле в методе __exit__, @contextmanager здесь вам не поможет.

Вы можете создать подкласс contextlib.GeneratorContextManager, чтобы избежать большей части работы.Это не задокументировано, так что используйте источник, Люк.

0 голосов
/ 13 марта 2017

Попробуйте переместить @contextmanager внизу списка декораторов.

...