from types import ClassType
from inspect import getargspec

class Signature(object):

    def __init__(self, obj):
        """Set entire state of object during instantiation"""
        error_msg = ("can only be constructed from a Python function, "
                    "method, class with an __init__ method, "
                    "or an instance with a __call__ method")
        try:
            if hasattr(obj, "im_func"):
                fxn_object = obj.im_func
            elif hasattr(obj, "func_code"):
                fxn_object = obj
            elif (hasattr(obj, "__call__") and not isinstance(obj, type) and
                  not isinstance(obj, ClassType)):
                fxn_object = obj.__call__.im_func
            elif (hasattr(obj, "__init__") and
                    (isinstance(obj, type) or isinstance(obj, ClassType))):
                fxn_object = obj.__init__.im_func
            else:
                raise TypeError(error_msg)
        except AttributeError:
            raise TypeError(error_msg)
        data = getargspec(fxn_object)
        if not data[3]:
            required_arg_cnt = len(data[0])
        else:
            required_arg_cnt = len(data[0]) - len(data[3])
        self.required_args = tuple(data[0][:required_arg_cnt])
        if not data[3]:
            self.default_args = ()
        else:
            self.default_args = tuple(zip(data[0][required_arg_cnt:],
                                          data[3]))
        self.excess_pos_args = bool(data[1])
        self.excess_kw_args = bool(data[2])

    def __str__(self):
        """Return a string representation of the signature, suitable for human
        consumption"""
        signature_parts = list(self.required_args)
        default_reprs = []
        for name, value in self.default_args:
            if hasattr(value, "__name__"):
                value_repr = value.__name__
            else:
                value_repr = repr(value)
            default_reprs.append("%s=%s" % (name, value_repr))
        signature_parts.extend(default_reprs)
        if self.excess_pos_args:
            signature_parts.append("*args")
        if self.excess_kw_args:
            signature_parts.append("**kwargs")
        return ", ".join(signature_parts)








