Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use python with statement for conditional execution?

I'm trying to write code that supports the following semantics:

with scope('action_name') as s:
  do_something()
  ...
do_some_other_stuff()

The scope, among other things (setup, cleanup) should decide if this section should run.
For instance, if the user configured the program to bypass 'action_name' than, after Scope() is evaluated do_some_other_stuff() will be executed without calling do_something() first.
I tried to do it using this context manager:

@contextmanager
def scope(action):
  if action != 'bypass':
    yield

but got RuntimeError: generator didn't yield exception (when action is 'bypass').
I am looking for a way to support this without falling back to the more verbose optional implementation:

with scope('action_name') as s:
  if s.should_run():
    do_something()
    ...
do_some_other_stuff()

Does anyone know how I can achieve this?
Thanks!

P.S. I am using python2.7

EDIT:
The solution doesn't necessarily have to rely on with statements. I just didn't know exactly how to express it without it. In essence, I want something in the form of a context (supporting setup and automatic cleanup, unrelated to the contained logic) and allowing for conditional execution based on parameters passed to the setup method and selected in the configuration.
I also thought about a possible solution using decorators. Example:

@scope('action_name') # if 'action_name' in allowed actions, do:
                      #   setup()
                      #   do_action_name()
                      #   cleanup()
                      # otherwise return
def do_action_name()
  do_something()

but I don't want to enforce too much of the internal structure (i.e., how the code is divided to functions) based on these scopes.
Does anybody have some creative ideas?

like image 865
Oren S Avatar asked Nov 30 '10 13:11

Oren S


1 Answers

You're trying to modify the expected behaviour of a basic language construct. That's never a good idea, it will just lead to confusion.

There's nothing wrong with your work-around, but you can simplify it just a bit.

@contextmanager 
def scope(action): 
  yield action != 'bypass'

with scope('action_name') as s: 
  if s: 
    do_something() 
    ... 
do_some_other_stuff() 

Your scope could instead be a class whose __enter__ method returns either a useful object or None and it would be used in the same fashion.

like image 114
Mark Ransom Avatar answered Oct 12 '22 11:10

Mark Ransom