<commit_before>from .exceptions import JSONConfigException
import numbers


_undefined = object()


class JSONConfigQueryError(JSONConfigException):
    """
    The base class of every exceptions thrown by this library during config queries.
    """
    def __init__(self, config_node, message):
        """
        :param config_node: An instance of one of the subclasses of _ConfigNode.
        You can use config_node.line and config_node.column to get the zero based
        line and column number of the error location in the config file.
        """
        message += ' [line=%s;col=%s]' % (config_node.line+1, config_node.column+1)
        super(JSONConfigQueryError, self).__init__(message)
        self.config_node = config_node


class JSONConfigValueMapperError(JSONConfigQueryError):
    """
    This is raised when someone fetches a config value by specifying the "mapper" parameter
    and the mapper function raises an exception. That exception is converted into this one.
    """
    def __init__(self, config_node, mapper_exception):
        """
        :param config_node:  An instance of one of the subclasses of _ConfigNode.
        :param mapper_exception: The exception instance that was raised during value conversion.
        It can be anything...
        """
        super(JSONConfigValueMapperError, self).__init__(config_node, 'Error converting config value: ' +
                                                         mapper_exception.message)
        self.mapper_exception = mapper_exception


class JSONConfigValueNotFoundError(JSONConfigQueryError):
    """
    Raised when the user tries to fetch a value that doesn't exist in the config.
    """
    def __init__(self, value_not_found):
        """
        :param value_not_found: A ValueNotFoundNode instance. Let's say that you query the
        config.servers[1].ip_address() value from the config but the config.servers array
        has only one item. In this case a JSONConfigValueNotFoundError is raised and
        value_not_found.parent_config_node is set to config.servers (that is the last existing
        component from our query path) and self.relative_path will be '[1].ip_address'.
        This way the error location points to the config.servers node and the error message
        says that you wanted to query it with the '[1].ip_address' relative_path that doesn't
        exist.
        """
        self.value_not_found = value_not_found
        path = []
        for component in value_not_found.missing_query_path:
            if isinstance(component, numbers.Integral):
                path.append('[%s]' % component)
            else:
                path.append('.' + component)
        self.relative_path = ''.join(path)
        message = 'Required config node not found. Missing query path: %s (relative to error location)' % self.relative_path
        super(JSONConfigValueNotFoundError, self).__init__(value_not_found.parent_config_node, message)


class JSONConfigNodeTypeError(JSONConfigQueryError):
    """
    This error is raised when you try to handle a config node by assuming its type
    to be something else than its actual type. For example you are trying to iterate
    over the key-value pairs of a json array or a simple boolean value or number.
    """
    def __init__(self, config_node, expected_type_name):
        """<commit_msg>added a TODO<commit_after>from .exceptions import JSONConfigException
import numbers


_undefined = object()


class JSONConfigQueryError(JSONConfigException):
    """
    The base class of every exceptions thrown by this library during config queries.
    """
    def __init__(self, config_node, message):
        """
        :param config_node: An instance of one of the subclasses of _ConfigNode.
        You can use config_node.line and config_node.column to get the zero based
        line and column number of the error location in the config file.
        """
        message += ' [line=%s;col=%s]' % (config_node.line+1, config_node.column+1)
        super(JSONConfigQueryError, self).__init__(message)
        self.config_node = config_node


class JSONConfigValueMapperError(JSONConfigQueryError):
    """
    This is raised when someone fetches a config value by specifying the "mapper" parameter
    and the mapper function raises an exception. That exception is converted into this one.
    """
    def __init__(self, config_node, mapper_exception):
        """
        :param config_node:  An instance of one of the subclasses of _ConfigNode.
        :param mapper_exception: The exception instance that was raised during value conversion.
        It can be anything...
        """
        super(JSONConfigValueMapperError, self).__init__(config_node, 'Error converting config value: ' +
                                                         mapper_exception.message)
        self.mapper_exception = mapper_exception


class JSONConfigValueNotFoundError(JSONConfigQueryError):
    """
    Raised when the user tries to fetch a value that doesn't exist in the config.
    """
    def __init__(self, value_not_found):
        """
        :param value_not_found: A ValueNotFoundNode instance. Let's say that you query the
        config.servers[1].ip_address() value from the config but the config.servers array
        has only one item. In this case a JSONConfigValueNotFoundError is raised and
        value_not_found.parent_config_node is set to config.servers (that is the last existing
        component from our query path) and self.relative_path will be '[1].ip_address'.
        This way the error location points to the config.servers node and the error message
        says that you wanted to query it with the '[1].ip_address' relative_path that doesn't
        exist.
        """
        self.value_not_found = value_not_found
        path = []
        for component in value_not_found.missing_query_path:
            if isinstance(component, numbers.Integral):
                path.append('[%s]' % component)
            else:
                path.append('.' + component)
        self.relative_path = ''.join(path)
        # TODO: improve the error message: it is possible to do so based on the info we have
        message = 'Required config node not found. Missing query path: %s (relative to error location)' % self.relative_path
        super(JSONConfigValueNotFoundError, self).__init__(value_not_found.parent_config_node, message)


class JSONConfigNodeTypeError(JSONConfigQueryError):
    """
    This error is raised when you try to handle a config node by assuming its type
    to be something else than its actual type. For example you are trying to iterate
    over the key-value pairs of a json array or a simple boolean value or number.
    """
    def __init__(self, config_node, expected_type_name):
        """
{'fraction_non_alphanumeric': 0.06910211267605634, 'fraction_numerical': 0.0014671361502347417, 'mean_word_length': 2.8976558033161806, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6056143', 'n_tokens_mistral': 1733, 'n_tokens_neox': 1708, 'n_words': 669}