python-makefun icon indicating copy to clipboard operation
python-makefun copied to clipboard

Provide an easier way to wrap a function whatever its mode (regular, generator, or generator coroutine)

Open smarie opened this issue 6 years ago • 1 comments

In many cases when we create function wrappers, we would like to have a single way to write the wrapper rather than handling both generator and regular modes with a if/else.

A good illustration is provided below:

https://github.com/smarie/python-pytest-harvest/blob/master/pytest_harvest/fixture_cache.py#L193

Maybe we could add a multi_mode_handler flag ? Setting it to True would require the handler to be written in a way that is independent from the wrapped mode (to be found... maybe a coroutine ?).

smarie avatar Mar 05 '19 12:03 smarie

I propose to add a mode argument instead, and to provide a helper companion as_generator function.

def create_wrapper(f):
 
    # use the helper to always have a generator
    genf = as_generator(f)

    @with_signature(f, mode=f)
    def my_handler( *args, **kwargs):
        # <init code>
        gen = genf(*args, **kwargs)
        for res in gen:
             # <intermediate code>
             yield res  # or yield anything else
        # <termination code>

    return my_handler

This would do the trick.

  • mode=f indicates that the generated function has the same mode than f (generator if generator, etc.). In that case the handler has to be itself a generator (nothing else is supported).
  • as_generator(f) is used to turn f into a generator if it is not already the case

The code above would work if foo is a normal function or a generator:

def foo(a):
    return "hello"

create_wrapper(foo)  # should be a normal function

def foo_g(a):
    yield "hello"
    yield "again"

create_wrapper(foo)  # should be a generator

smarie avatar Mar 05 '19 12:03 smarie