smarie / python-makefun

Dynamically create python functions with a proper signature.
https://smarie.github.io/python-makefun/
BSD 3-Clause "New" or "Revised" License
119 stars 16 forks source link

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

Open smarie opened 5 years ago

smarie commented 5 years ago

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 commented 5 years ago

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.

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