<commit_before>import collections
import grp
import os
import pwd
import socket

import netaddr
from pyroute2.iproute import IPRoute

from hades.config.base import ConfigError


class OptionCheckError(ConfigError):
    pass


def qualified_name(type_):
    if type_.__module__ is None or type_.__module__ == 'builtins':
        return type_.__qualname__
    else:
        return type_.__module__ + '.' + type_.__qualname__


def check_option(config, option, value, runtime_checks=False):
    if option.type is not None and not isinstance(value, option.type):
        expected = qualified_name(option.type)
        got = qualified_name(type(value))
        raise OptionCheckError("Must be a subtype of {}, was {}"
                               .format(expected, got), option=option.__name__)
    if option.static_check:
        option.static_check(config, value)
    if runtime_checks and option.runtime_check:
        option.runtime_check(config, value)


def greater_than(threshold):
    # noinspection PyDecorator,PyUnusedLocal
    @classmethod
    def checker(cls, config, value):
        if value <= threshold:
            raise OptionCheckError("Must be greater than {}".format(threshold),
                                   option=cls.__name__)
    return checker


def between(low, high):
    # noinspection PyDecorator,PyUnusedLocal
    @classmethod
    def checker(cls, config, value):
        if not (low <= value <= high):
            raise OptionCheckError("Must be between {} and {} inclusively"
                                   .format(low, high), option=cls.__name__)
    return checker


def mapping(key_check=None, value_check=None):
    # noinspection PyDecorator
    @classmethod
    def f(cls, config, value):
        for k, v in value.items():
            try:
                if key_check is not None:
                    key_check.__get__(None, cls)(config, k)
                if value_check is not None:
                    value_check.__get__(None, cls)(config, v)
            except ConfigError as e:
                raise OptionCheckError("Error in key {}: {}"
                                       .format(k, e.args[0]),
                                       option=option.__name__)
    return f


def type_is(types):
    # noinspection PyDecorator,PyUnusedLocal
    @classmethod
    def f(cls, config, value):
        if not isinstance(value, types):
            raise OptionCheckError("Must be an instance of {}"
                                   .format(', '.join(types)),
                                   option=cls.__name__)
    return f


# noinspection PyDecorator,PyUnusedLocal
@classmethod
def not_empty(cls, config, value):
    if len(value) <= 0:
        raise OptionCheckError("Must not be empty", option=cls.__name__)


def all(*checks):
    # noinspection PyDecorator
    @classmethod
    def f(cls, config, value):
        for check in checks:
            check.__get__(None, cls)(config, value)
    return f


# noinspection PyDecorator,PyUnusedLocal
@classmethod
def network_ip(cls, config, value):
    if value.ip == value.value:
        raise OptionCheckError("The host part of {} is the network address of "
                               "the subnet. Must be an IP of the subnet."
                               .format(value), option=cls.__name__)
    # Prefix length 31 is special, see RFC 3021
    if value.prefixlen != 31 and value.ip == value.broadcast:
        raise OptionCheckError("The host part of {} is the broadcast address "
                               "of the subnet. Must be an IP of the subnet."
                               .format(value), option=cls.__name__)


# noinspection PyDecorator,PyUnusedLocal
@classmethod
def directory_exists(cls, config, value):
    if not os.path.exists(value):
        raise OptionCheckError("Directory {} does not exists".format(value),
                               option=cls.__name__)
    if not os.path.isdir(value):
        raise OptionCheckError("{} is not a directory".format(value),
                               option=cls.__name__)


# noinspection PyDecorator,PyUnusedLocal
@classmethod
def file_exists(cls, config, value):
    if not os.path.exists(value):
        raise OptionCheckError("File {} does not exists".format(value),
                               option=cls.__name__)
    if not os.path.isfile(value):
        raise OptionCheckError("{} is not a file".format(value),
                               option=cls.__name__)


# noinspection PyDecorator
@classmethod
def file_creatable(cls, config, value):
    parent = os.path.dirname(value)
    directory_exists.__get__(None, cls)(config, parent)


# noinspection PyDecorator,PyUnusedLocal
@classmethod
def interface_exists(cls, config, value):
    try:
        socket.if_nametoindex(value)
    except OSError:
        raise OptionCheckError("Interface {} not found".format(value),
                               option=cls.__name__)


# noinspection PyDecorator,PyUnusedLocal
@classmethod
def address_exists(cls, config, value):
    ip = IPRoute()
    if value.version == 4:
        family = socket.AF_INET
    elif value.version == 6:
        family = socket.AF_INET6
    else:
        raise AssertionError("Unknown version {}".format(value.version))
    if ip.get_addr(family=family, address=value.ip, prefixlen=value.prefixlen):
        raise OptionCheckError("No such address {}".format(value),
                               option=cls.__name__)


def ip_range_in_network(network_config):
    # noinspection PyDecorator
    @classmethod
    def checker(cls, config, value):
        network = config[network_config]
        first = netaddr.IPAddress(value.first)
        last = netaddr.IPAddress(value.last)
        if first not in network or last not in network:
            raise OptionCheckError("Range not contained in network {}"
                                   .format(network), option=cls.__name__)
    return checker


# noinspection PyDecorator,PyUnusedLocal
@classmethod
def user_exists(cls, config, value):
    try:
        return pwd.getpwnam(value)
    except KeyError:
        raise OptionCheckError("User {} does not exists".format(value),
                               option=cls.__name__)


# noinspection PyDecorator,PyUnusedLocal
@classmethod
def group_exists(cls, config, value):
    try:
        return grp.getgrnam(value)
    except KeyError:
        raise OptionCheckError("Group {} does not exists".format(value),
                               option=cls.__name__)


# noinspection PyDecorator
@classmethod
def has_key(name, value, *keys):
    obj = value
    path = []
    for key in keys:
        if not isinstance(obj, collections.Mapping):
            raise OptionCheckError("{} is not a Mapping type"
                                   .format('->'.join(path)),
                                   option=cls.__name__)
        path.append(key)
        try:
            obj = obj.get(key)
        except KeyError:
            raise OptionCheckError("Missing key {}".format('->'.join(path)),
                                   option=cls.__name__)


def user_mapping_for_user_exists(user_option_name):
    # noinspection PyDecorator
    @classmethod
    def checker(cls, config, value):<commit_msg>Fix and rename has_key<commit_after>import collections
import grp
import os
import pwd
import socket

import netaddr
from pyroute2.iproute import IPRoute

from hades.config.base import ConfigError


class OptionCheckError(ConfigError):
    pass


def qualified_name(type_):
    if type_.__module__ is None or type_.__module__ == 'builtins':
        return type_.__qualname__
    else:
        return type_.__module__ + '.' + type_.__qualname__


def check_option(config, option, value, runtime_checks=False):
    if option.type is not None and not isinstance(value, option.type):
        expected = qualified_name(option.type)
        got = qualified_name(type(value))
        raise OptionCheckError("Must be a subtype of {}, was {}"
                               .format(expected, got), option=option.__name__)
    if option.static_check:
        option.static_check(config, value)
    if runtime_checks and option.runtime_check:
        option.runtime_check(config, value)


def greater_than(threshold):
    # noinspection PyDecorator,PyUnusedLocal
    @classmethod
    def checker(cls, config, value):
        if value <= threshold:
            raise OptionCheckError("Must be greater than {}".format(threshold),
                                   option=cls.__name__)
    return checker


def between(low, high):
    # noinspection PyDecorator,PyUnusedLocal
    @classmethod
    def checker(cls, config, value):
        if not (low <= value <= high):
            raise OptionCheckError("Must be between {} and {} inclusively"
                                   .format(low, high), option=cls.__name__)
    return checker


def mapping(key_check=None, value_check=None):
    # noinspection PyDecorator
    @classmethod
    def f(cls, config, value):
        for k, v in value.items():
            try:
                if key_check is not None:
                    key_check.__get__(None, cls)(config, k)
                if value_check is not None:
                    value_check.__get__(None, cls)(config, v)
            except ConfigError as e:
                raise OptionCheckError("Error in key {}: {}"
                                       .format(k, e.args[0]),
                                       option=option.__name__)
    return f


def type_is(types):
    # noinspection PyDecorator,PyUnusedLocal
    @classmethod
    def f(cls, config, value):
        if not isinstance(value, types):
            raise OptionCheckError("Must be an instance of {}"
                                   .format(', '.join(types)),
                                   option=cls.__name__)
    return f


# noinspection PyDecorator,PyUnusedLocal
@classmethod
def not_empty(cls, config, value):
    if len(value) <= 0:
        raise OptionCheckError("Must not be empty", option=cls.__name__)


def all(*checks):
    # noinspection PyDecorator
    @classmethod
    def f(cls, config, value):
        for check in checks:
            check.__get__(None, cls)(config, value)
    return f


# noinspection PyDecorator,PyUnusedLocal
@classmethod
def network_ip(cls, config, value):
    if value.ip == value.value:
        raise OptionCheckError("The host part of {} is the network address of "
                               "the subnet. Must be an IP of the subnet."
                               .format(value), option=cls.__name__)
    # Prefix length 31 is special, see RFC 3021
    if value.prefixlen != 31 and value.ip == value.broadcast:
        raise OptionCheckError("The host part of {} is the broadcast address "
                               "of the subnet. Must be an IP of the subnet."
                               .format(value), option=cls.__name__)


# noinspection PyDecorator,PyUnusedLocal
@classmethod
def directory_exists(cls, config, value):
    if not os.path.exists(value):
        raise OptionCheckError("Directory {} does not exists".format(value),
                               option=cls.__name__)
    if not os.path.isdir(value):
        raise OptionCheckError("{} is not a directory".format(value),
                               option=cls.__name__)


# noinspection PyDecorator,PyUnusedLocal
@classmethod
def file_exists(cls, config, value):
    if not os.path.exists(value):
        raise OptionCheckError("File {} does not exists".format(value),
                               option=cls.__name__)
    if not os.path.isfile(value):
        raise OptionCheckError("{} is not a file".format(value),
                               option=cls.__name__)


# noinspection PyDecorator
@classmethod
def file_creatable(cls, config, value):
    parent = os.path.dirname(value)
    directory_exists.__get__(None, cls)(config, parent)


# noinspection PyDecorator,PyUnusedLocal
@classmethod
def interface_exists(cls, config, value):
    try:
        socket.if_nametoindex(value)
    except OSError:
        raise OptionCheckError("Interface {} not found".format(value),
                               option=cls.__name__)


# noinspection PyDecorator,PyUnusedLocal
@classmethod
def address_exists(cls, config, value):
    ip = IPRoute()
    if value.version == 4:
        family = socket.AF_INET
    elif value.version == 6:
        family = socket.AF_INET6
    else:
        raise AssertionError("Unknown version {}".format(value.version))
    if ip.get_addr(family=family, address=value.ip, prefixlen=value.prefixlen):
        raise OptionCheckError("No such address {}".format(value),
                               option=cls.__name__)


def ip_range_in_network(network_config):
    # noinspection PyDecorator
    @classmethod
    def checker(cls, config, value):
        network = config[network_config]
        first = netaddr.IPAddress(value.first)
        last = netaddr.IPAddress(value.last)
        if first not in network or last not in network:
            raise OptionCheckError("Range not contained in network {}"
                                   .format(network), option=cls.__name__)
    return checker


# noinspection PyDecorator,PyUnusedLocal
@classmethod
def user_exists(cls, config, value):
    try:
        return pwd.getpwnam(value)
    except KeyError:
        raise OptionCheckError("User {} does not exists".format(value),
                               option=cls.__name__)


# noinspection PyDecorator,PyUnusedLocal
@classmethod
def group_exists(cls, config, value):
    try:
        return grp.getgrnam(value)
    except KeyError:
        raise OptionCheckError("Group {} does not exists".format(value),
                               option=cls.__name__)


def has_keys(*keys):
    # noinspection PyDecorator,PyUnusedLocal
    @classmethod
    def f(cls, config, value):
        obj = value
        checked = []

        for key in keys:
            if not isinstance(obj, collections.Mapping):
                path = cls.__name__ + ''.join(map('[{!r}]'.format, checked))
                raise OptionCheckError("must be a mapping type like dict",
                                       option=path)
            checked.append(key)
            try:
                obj = obj[key]
            except KeyError:
                path = cls.__name__ + ''.join(map('[{!r}]'.format, checked))
                raise OptionCheckError("Missing key", option=path) from None
    return f


def user_mapping_for_user_exists(user_option_name):
    # noinspection PyDecorator
    @classmethod
    def checker(cls, config, value):
{'fraction_non_alphanumeric': 0.09237415992319298, 'fraction_numerical': 0.0019201755589082431, 'mean_word_length': 2.252955610082534, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4860821', 'n_tokens_mistral': 4064, 'n_tokens_neox': 3960, 'n_words': 1063}