@staticmethod<EOL><INDENT>def inspect_obj(obj):<DEDENT>
skip_params = <NUM_LIT:0><EOL>if inspect.isfunction(obj):<EOL><INDENT>name = obj.__name__<EOL>inspect_obj = obj<EOL>skip_params = <NUM_LIT:0><EOL><DEDENT>elif inspect.ismethod(obj):<EOL><INDENT>name = obj.im_func.__name__<EOL>inspect_obj = obj<EOL>skip_params = <NUM_LIT:1>  <EOL><DEDENT>elif inspect.isclass(obj):<EOL><INDENT>inspect_obj = None<EOL>if hasattr(obj, '<STR_LIT>') and '<STR_LIT>' in obj.__dict__:<EOL><INDENT>inspect_obj = obj.__new__<EOL><DEDENT>elif hasattr(obj, '<STR_LIT>'):<EOL><INDENT>inspect_obj = obj.__init__<EOL><DEDENT>else:<EOL><INDENT>raise ProgrammerError(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' % str(obj))<EOL><DEDENT>name = obj.__name__<EOL>if hasattr(obj, '<STR_LIT>'):<EOL><INDENT>name = obj.config_name<EOL><DEDENT>if not inspect.ismethod(inspect_obj)and not inspect.isfunction(inspect_obj):<EOL><INDENT>raise ProgrammerError(<EOL>'<STR_LIT>'<EOL>% (str(obj), inspect_obj.__name__, type(inspect_obj)))<EOL><DEDENT>skip_params = <NUM_LIT:1>  <EOL><DEDENT>else:<EOL><INDENT>raise ProgrammerError(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' % (repr(obj), type(obj)))<EOL><DEDENT>argspec = inspect.getargspec(inspect_obj)<EOL>if argspec.varargs is not None or argspec.keywords is not None:<EOL><INDENT>raise ProgrammerError(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' % repr(obj))<EOL><DEDENT>if not all(isinstance(arg, string_types) for arg in argspec.args):<EOL><INDENT>raise ProgrammerError(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>% (repr(obj), argspec.args))<EOL><DEDENT>defaults = argspec.defaults or []<EOL>i_defaults = len(argspec.args) - len(defaults)<EOL>return {<EOL>'<STR_LIT:name>': name,<EOL>'<STR_LIT>': argspec.args[skip_params:i_defaults],<EOL>'<STR_LIT>': dict([(k, defaults[i])<EOL>for i, k in enumerate(argspec.args[i_defaults:])]),<EOL>}<EOL>
Learn what there is to be learned from our target.

        Given an object at `obj`, which must be a function, method or
        class, return a configuration *discovered* from the name of
        the object and its parameter list. This function is
        responsible for doing runtime reflection and providing
        understandable failure modes.

        The return value is a dictionary with three keys: ``name``,
        ``required`` and ``defaults``. ``name`` is the name of the
        function/method/class. ``required`` is a list of parameters
        *without* default values. ``defaults`` is a dictionary mapping
        parameter names to default values. The sets of parameter names in
        ``required`` and ``defaults`` are disjoint.

        When given a class, the parameters are taken from its ``__init__``
        method.

        Note that this function is purposefully conservative in the things
        that is will auto-configure. All of the following things will result
        in a :exc:`yakonfig.ProgrammerError` exception being raised:

        1. A parameter list that contains tuple unpacking. (This is invalid
           syntax in Python 3.)
        2. A parameter list that contains variable arguments (``*args``) or
           variable keyword words (``**kwargs``). This restriction forces
           an auto-configurable to explicitly state all configuration.

        Similarly, if given an object that isn't a function/method/class, a
        :exc:`yakonfig.ProgrammerError` will be raised.

        If reflection cannot be performed on ``obj``, then a ``TypeError``
        is raised.