Search code examples
pythondecoratorpython-decorators

How to use Decorator on function which was created from a the return value of a closure?


I have got the following decorators:

def msg_factory(*, prefix: str, **styles: Dict[str, Any]):
    def decorator_msg_factory(func):
        @functools.wraps(func)
        def wrapper_msg_factory(*args, **kwargs):
            msg = func(*args, **kwargs)
            return typer.echo(f"{typer.style(prefix, **styles)}: {msg}")

        return wrapper_msg_factory

    return decorator_msg_factory



error_msg = msg_factory(prefix="ERROR", fg=typer.colors.BLACK, bg=typer.colors.RED)
warn_msg = msg_factory(prefix="WARN", fg=typer.colors.BLACK, bg=typer.colors.YELLOW)
info_msg = msg_factory(prefix="INFO", fg=typer.colors.BLACK, bg=typer.colors.GREEN)

I can use it like this:

@info_msg
def init_template_created_successfully() -> str:
    msg_0 = "sdasdasd:\n\n"
    msg_1 = "1. dasdasd\n"
    return msg_0 + msg_1

This works fine, but I want to use a factory function for the messages like this:

def create_multiline_message_function(*messages: str) -> str:
    def multiline_string():
        return "\n".join(messages)

    return multiline_string



init_template_created_successfully = create_multiline_message_function(
    "1. sdasda",
    "2. sdasda"
)

This does not work unfortunately and results in a syntax Error. It my approach possible? If yes, how ?

@info_msg
init_template_created_successfully 

Solution

  • Python decorators are syntax-sugar, so

    @mydecorator
    def myfunction():
        ...
    

    is equivalent to

    def myfunction():
        ...
    myfunction = mydecorator(myfunction)
    

    as you might observe latter might be applied independetly from def. For futher discussion see PEP 318.