# Path: esc/oops.py
# class ProgrammingError(EscError):
#     r"""
#     Indicates an error caused by incorrectly written or defined esc
#     plugins. This includes modes, menus, operations, and so on.
#     It does not include runtime errors within operation functions
#     themselves; these are :class:`FunctionExecutionError`\ s.
#     """
# 
# Path: esc/util.py
# def magic_call(func, available_kwargs):
#     """
#     Call /func/, allowing it to pick and choose from a set of arguments. This
#     works much like pytest's test fixtures do -- the framework has a set of
#     available data or functions which are selected by name by user functions.
# 
#     /available_kwargs/ is a dictionary-like object mapping parameter names to
#     values. magic_call double-splats these values to any matching arguments
#     in the function's signature, ignoring any that aren't named in the
#     signature.
# 
#     If the function's signature contains an argument that isn't in the
#     dictionary, and thus can't be bound, raise a ProgrammingError.
#     """
#     sig = inspect.signature(func)
#     unavailable, requested = (list(i)
#                               for i in partition(available_kwargs.__contains__,
#                                                  sig.parameters.keys()))
# 
#     if unavailable:
#         raise ProgrammingError(
#             f"The function '{func.__name__}' "
#             f"({inspect.getfile(func)}:{inspect.getsourcelines(func)[1]}) "
#             f"requested the following arguments which are not available: "
#             f"{', '.join(unavailable)}. "
#             f"Available arguments are as follows: "
#             f"{', '.join(available_kwargs.keys())}.")
# 
#     return func(**{k: v for k, v in available_kwargs.items() if k in requested})


import pytest
from esc.oops import ProgrammingError
from esc.util import magic_call
"""
Tests for util.py

The vast majority of the module's functions are pure and are tested via
convenient doctests. The few functions where that's ugly are tested here.
"""




def test_magic_call():
    """
    We can magic-call a function with more arguments than it needs,
    and the order doesn't matter.
    """
    def f(y, x):
        return x - y

    kwargs = {'x': 2, 'y': 3, 'z': 8}
    assert magic_call(f, kwargs) == -1


def test_magic_call_missing_args():
    "However, the function can't request arguments we don't have."
    def f(x, y):
        return x + y

    kwargs = {'x': 2}
    with pytest.raises(ProgrammingError) as excinfo:

# Path: esc/oops.py
# class ProgrammingError(EscError):
#     r"""
#     Indicates an error caused by incorrectly written or defined esc
#     plugins. This includes modes, menus, operations, and so on.
#     It does not include runtime errors within operation functions
#     themselves; these are :class:`FunctionExecutionError`\ s.
#     """
# 
# Path: esc/util.py
# def magic_call(func, available_kwargs):
#     """
#     Call /func/, allowing it to pick and choose from a set of arguments. This
#     works much like pytest's test fixtures do -- the framework has a set of
#     available data or functions which are selected by name by user functions.
# 
#     /available_kwargs/ is a dictionary-like object mapping parameter names to
#     values. magic_call double-splats these values to any matching arguments
#     in the function's signature, ignoring any that aren't named in the
#     signature.
# 
#     If the function's signature contains an argument that isn't in the
#     dictionary, and thus can't be bound, raise a ProgrammingError.
#     """
#     sig = inspect.signature(func)
#     unavailable, requested = (list(i)
#                               for i in partition(available_kwargs.__contains__,
#                                                  sig.parameters.keys()))
# 
#     if unavailable:
#         raise ProgrammingError(
#             f"The function '{func.__name__}' "
#             f"({inspect.getfile(func)}:{inspect.getsourcelines(func)[1]}) "
#             f"requested the following arguments which are not available: "
#             f"{', '.join(unavailable)}. "
#             f"Available arguments are as follows: "
#             f"{', '.join(available_kwargs.keys())}.")
# 
#     return func(**{k: v for k, v in available_kwargs.items() if k in requested})


# Path: tests/esc/test_util.py
import pytest
from esc.oops import ProgrammingError
from esc.util import magic_call

"""
Tests for util.py

The vast majority of the module's functions are pure and are tested via
convenient doctests. The few functions where that's ugly are tested here.
"""




def test_magic_call():
    """
    We can magic-call a function with more arguments than it needs,
    and the order doesn't matter.
    """
    def f(y, x):
        return x - y

    kwargs = {'x': 2, 'y': 3, 'z': 8}
    assert magic_call(f, kwargs) == -1


def test_magic_call_missing_args():
    "However, the function can't request arguments we don't have."
    def f(x, y):
        return x + y

    kwargs = {'x': 2}
    with pytest.raises(ProgrammingError) as excinfo:

        magic_call(f, kwargs)