# Path: microcosm_pubsub/chain/decorators.py
# BINDS = "_binds"
# 
# EXTRACTS = "_extracts"
# 
# Path: microcosm_pubsub/chain/exceptions.py
# class ContextKeyNotFound(Exception):
#     def __init__(self, key_error: KeyError, func):
#         context_key, *_ = key_error.args
#         super().__init__(f"Failed to find context key `{context_key}` during evaluation of `{func}`")


from functools import WRAPPER_ASSIGNMENTS, wraps
from inspect import Parameter, Signature, signature
from microcosm_pubsub.chain.decorators import BINDS, EXTRACTS
from microcosm_pubsub.chain.exceptions import ContextKeyNotFound


def save_to_context_by_func_name(context, func, assigned=DEFAULT_ASSIGNED):
    """
    Decorate a function - save to a context (dictionary) the function return value
    if the function is not signed by EXTRACTS and it's name starts with "extract_"

    """
    if (
        hasattr(func, EXTRACTS) or
        not hasattr(func, "__name__") or
        not func.__name__.startswith(EXTRACT_PREFIX)
    ):
        return func
    name = func.__name__[len(EXTRACT_PREFIX):]

    @wraps(func, assigned=assigned + WRAPPER_ASSIGNMENTS)
    def decorate(*args, **kwargs):
        value = func(*args, **kwargs)
        context[name] = value
        return value
    return decorate


def temporarily_replace_context_keys(context, func, assigned=DEFAULT_ASSIGNED):
    """
    Decorate a function - temporarily updates the context keys while running the function
    Updates the context if the function is marked by @binds decorator.

    """

# Path: microcosm_pubsub/chain/decorators.py
# BINDS = "_binds"
# 
# EXTRACTS = "_extracts"
# 
# Path: microcosm_pubsub/chain/exceptions.py
# class ContextKeyNotFound(Exception):
#     def __init__(self, key_error: KeyError, func):
#         context_key, *_ = key_error.args
#         super().__init__(f"Failed to find context key `{context_key}` during evaluation of `{func}`")


# Path: microcosm_pubsub/chain/context_decorators.py
from functools import WRAPPER_ASSIGNMENTS, wraps
from inspect import Parameter, Signature, signature
from microcosm_pubsub.chain.decorators import BINDS, EXTRACTS
from microcosm_pubsub.chain.exceptions import ContextKeyNotFound



def save_to_context_by_func_name(context, func, assigned=DEFAULT_ASSIGNED):
    """
    Decorate a function - save to a context (dictionary) the function return value
    if the function is not signed by EXTRACTS and it's name starts with "extract_"

    """
    if (
        hasattr(func, EXTRACTS) or
        not hasattr(func, "__name__") or
        not func.__name__.startswith(EXTRACT_PREFIX)
    ):
        return func
    name = func.__name__[len(EXTRACT_PREFIX):]

    @wraps(func, assigned=assigned + WRAPPER_ASSIGNMENTS)
    def decorate(*args, **kwargs):
        value = func(*args, **kwargs)
        context[name] = value
        return value
    return decorate


def temporarily_replace_context_keys(context, func, assigned=DEFAULT_ASSIGNED):
    """
    Decorate a function - temporarily updates the context keys while running the function
    Updates the context if the function is marked by @binds decorator.

    """

    binds = getattr(func, BINDS, None)