Try to get the given attribute/function result for the given value.

        If ``args`` or ``kwargs`` are passed, the attribute got from ``value`` must be callable.
        They will be passed anyway (using ``[]`` and ``{}`` as default values) if the attribute
        is a function.

        Arguments
        ---------
        value : object
            Instance of the class hold in ``self.source``
        attribute : str
            Name of the attribute to retrieve. Must be available through ``self.attributes``
        args : list, default ``None``
            If defined, list of non-named arguments that will be passed to the attribute if it's
            callable.
        kwargs : dict, default ``None``
            If defined, list of named arguments that will be passed to the attribute if it's
            callable.

        Returns
        -------
        Value of the current attribute/function result for the ``value`` instance.

        Raises
        ------
        dataql.solvers.exceptions.NotSolvable
            When the value is not an instance of the source class
        dataql.solvers.exceptions.AttributeNotFound
            When the attribute is not allowed

        Example
        -------

        >>> from datetime import date
        >>> d = date(2015, 6, 1)
        >>> s = Source(date, ['day', 'strftime', ('str', str)])
        >>> s.solve(d, 'day')
        1
        >>> s.solve(d, 'strftime', ['%F'])
        '2015-06-01'
        >>> s.solve(d, 'str')
        '2015-06-01'
        >>> s.solve('a string', ['day']) # doctest: +ELLIPSIS
        Traceback (most recent call last):
        dataql.solvers.exceptions.NotSolvable: The `datetime.date` source can only...
        >>> s.solve(d, 'month') # doctest: +ELLIPSIS
        Traceback (most recent call last):
        dataql.solvers.exceptions.AttributeNotFound: `month` is not an allowed...for `datetime.date`
        >>> s.solve(d, 'day', ['foo'])
        Traceback (most recent call last):
        TypeError: 'int' object is not callable

def solve(self, value, attribute, args=None, kwargs=None):
        """Try to get the given attribute/function result for the given value.

        If ``args`` or ``kwargs`` are passed, the attribute got from ``value`` must be callable.
        They will be passed anyway (using ``[]`` and ``{}`` as default values) if the attribute
        is a function.

        Arguments
        ---------
        value : object
            Instance of the class hold in ``self.source``
        attribute : str
            Name of the attribute to retrieve. Must be available through ``self.attributes``
        args : list, default ``None``
            If defined, list of non-named arguments that will be passed to the attribute if it's
            callable.
        kwargs : dict, default ``None``
            If defined, list of named arguments that will be passed to the attribute if it's
            callable.

        Returns
        -------
        Value of the current attribute/function result for the ``value`` instance.

        Raises
        ------
        dataql.solvers.exceptions.NotSolvable
            When the value is not an instance of the source class
        dataql.solvers.exceptions.AttributeNotFound
            When the attribute is not allowed

        Example
        -------

        >>> from datetime import date
        >>> d = date(2015, 6, 1)
        >>> s = Source(date, ['day', 'strftime', ('str', str)])
        >>> s.solve(d, 'day')
        1
        >>> s.solve(d, 'strftime', ['%F'])
        '2015-06-01'
        >>> s.solve(d, 'str')
        '2015-06-01'
        >>> s.solve('a string', ['day']) # doctest: +ELLIPSIS
        Traceback (most recent call last):
        dataql.solvers.exceptions.NotSolvable: The `datetime.date` source can only...
        >>> s.solve(d, 'month') # doctest: +ELLIPSIS
        Traceback (most recent call last):
        dataql.solvers.exceptions.AttributeNotFound: `month` is not an allowed...for `datetime.date`
        >>> s.solve(d, 'day', ['foo'])
        Traceback (most recent call last):
        TypeError: 'int' object is not callable

        """

        if not isinstance(value, self.source) and (
                not self.allow_class or value is not self.source):
            raise NotSolvable(self, value)

        attr = None
        if attribute in self.attributes:
            attr = self.attributes[attribute]
        else:
            for parent_source in self.parent_sources:
                if attribute in parent_source.attributes:
                    attr = parent_source.attributes[attribute]
                    break

            if attr is None:
                raise AttributeNotFound(attribute, self)

        try:
            return attr.solve(value, args, kwargs)
        except AttributeNotFound:
            # Raise an ``AttributeError`` with ``self`` as source.
            raise AttributeNotFound(attr, self)