The code looks rather complicated. Instead of trying to understand it, I'd just like to point to NickC's answer to the linked SO question.
If I add **kwargs to his optional_arg_decorator like this...
def optional_arg_decorator(fn): def wrapped_decorator(*args, **kwargs): if len(args) == 1 and len(kwargs) == 0 and callable(args[0]): return fn(args[0]) else: def real_decorator(decoratee): return fn(decoratee, *args, **kwargs) return real_decorator return wrapped_decorator ...and adapt your decorators like this, I'm getting the same output from the test cases.
from functools import wraps @optional_arg_decorator def my_text_decorator(f, start_val="-=[", end_val="]=-"): @wraps(f) def wrapper(*args, **kwargs): return "".join([f.__name__, ' ', start_val, f(*args, **kwargs), end_val]) return wrapper @optional_arg_decorator def my_text_decorator2(f, start_val, end_val="]=-"): @wraps(f) def wrapper(*args, **kwargs): return "".join([f.__name__, ' ', start_val, f(*args, **kwargs), end_val]) return wrapper