# -*- coding: utf-8 mode: python -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
import i_need_py23

"""Des fonctions pour travailler avec les fonctions.
"""

__all__ = ('apply_args', 'unpack_results')

from types import MethodType, FunctionType

from uio import _s
from base import isseq

def apply_args(func, *args, **kw):
    u"""Appliquer à la fonction func les arguments args, en tenant compte du
    nombre de ses arguments et en ignorant les arguments "en trop".

    Par exemple, si f est défini ainsi:

        def f(a, b):
            pass

    Alors:

        apply_args(f, 1, 2, 3)

    Est équivalent à:

        apply(f, (1, 2))
    """
    f = func
    ac_offset = 0
    if type(f) is MethodType:
        f = f.im_func
        ac_offset = 1
    if type(f) is not FunctionType:
        raise ValueError("func must be a function")
    argcount = f.func_code.co_argcount - ac_offset
    args = args[:argcount]
    return func(*args, **kw)

def unpack_results(results, *defaults):
    u"""results étant une valeur scalaire ou une séquence, retourner une
    séquence ayant le même nombre de valeurs de defaults, et en fournissant
    les valeurs de defaults si elles ne sont pas présentes dans results.

    >>> unpack_results((1,2), "a", "b", "c")
    (1, 2, 'c')
    >>> unpack_results("x", "a", "b", "c")
    ('x', 'b', 'c')
    """
    if not isseq(results): results = (results,)
    expected = len(defaults)
    got = len(results)
    head = tuple(results[:expected])
    if got < expected: tail = tuple(defaults[-(expected - got):])
    else: tail = ()
    return head + tail
