Question

Lets's see this example:

with mycontextmanager(arg1='value', arg2=False):
    print 'Executed'

Is there a way to not execute code block (print 'Executed') within a context manager based on argument, eg: when arg2 is not False?

Was it helpful?

Solution

An other option is to use a special ConditionalExecution context manager whose __enter__ methods returns an action that conditionally raises a SkipExecution exception. The __exit__ method suppresses only this exception. Something like the following:

class SkipExecution(Exception): pass

class ConditionalExecution(object):
    def __init__(self, value, arg):
        self.value = value
        self.arg = arg
    def __enter__(self):
        def action():
            if not self.arg:
                raise SkipExecution()
        return action
    def __exit__(self, exc_type, exc_value, tb):
        if exc_type is SkipExecution:
            return True
        return False

Used as:

In [17]: with ConditionalExecution(1, True) as check_execution:
    ...:     check_execution()
    ...:     print('Hello')
    ...:     
Hello

In [18]: with ConditionalExecution(1, False) as check_execution:
    ...:     check_execution()
    ...:     print('Hello')

In [19]: 

However the problem is that you have to add a call to the value returned.

The problem is that __exit__ is called if and only if __enter__ returned succesfully, which means you can't raise an exception in __enter__ to block the execution of the code block. If you want you can modify this solution so that the call to check_execution() can be done in the first line, like:

In [29]: with ConditionalExecution(1, True) as check_execution, check_execution():
    ...:     print('Hello')
Hello

In [30]: with ConditionalExecution(1, False) as check_execution, check_execution():
    ...:     print('Hello')

Using a Skipper helper-context manager:

class SkipExecution(Exception): pass

class Skipper(object):
    def __init__(self, func):
        self.func = func
    def __call__(self):
        return self.func() or self
    def __enter__(self):
        return self
    def __exit__(self, *args):
        pass

class ConditionalExecution(object):
    def __init__(self, value, arg):
        self.value = value
        self.arg = arg
    def __enter__(self):
        def action():
            if not self.arg:
                raise SkipExecution()
        return Skipper(action)
    def __exit__(self, exc_type, exc_value, tb):
        if exc_type is SkipExecution:
            return True
        return False

I don't think there is anyway to do this without at least an explicit function call as in the above example.

OTHER TIPS

Perhaps like this, assuming your context manager supports a "whatever" property which exposes the value it got in arg2 when initialized:

with mycontextmanager(arg1='value', arg2=False) as ctx:
    if ctx.whatever:
        print 'Executed'
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top