<commit_before># Copyright Hybrid Logic Ltd.  See LICENSE file for details.
# -*- test-case-name: flocker.node.test.test_config -*-

"""
APIs for parsing and validating configuration.
"""

from __future__ import unicode_literals, absolute_import

import math
import os
import re
import types

from twisted.python.filepath import FilePath

from yaml import safe_dump
from zope.interface import Interface, implementer

from ._model import (
    Application, AttachedVolume, Deployment, Link,
    DockerImage, Node, Port, RestartAlways, RestartNever, RestartOnFailure,
)


class IApplicationConfiguration(Interface):
    """
    A class to detect and parse an application configuration  in a given
    format, mapping configuration to a ``dict`` of keys specifying application
    names mapped to values of ``Application`` instances.
    """
    def is_valid_format():
        """
        Detect if the supplied application configuration is in a format
        compatible with this configuration parser.

        Note that "valid format" does not necessarily translate to
        "valid configuration"; this method should only indicate whether the
        supplied configuration's outermost structure is such that it should
        be treated and parsed as a configuration of this parser's format.
        Further validation should be done during the parsing stage.

        :returns: A ``bool`` indicating ``True`` for a fig-style configuration
            or ``False`` if fig-style is not detected.
        """

    def applications():
        """
        Returns the ``Application`` instances parsed from the supplied
        configuration.

        This method should only be called after valdiating the format
        with a call to ``is_valid_format``.

        This method should only be called once, in that calling it
        multiple times will re-parse an already parsed config.

        :returns: A ``dict`` mapping application names to ``Application``
            instances.
        """


class ConfigurationError(Exception):
    """
    Some part of the supplied configuration was wrong.

    The exception message will include some details about what.
    """


def _check_type(value, types, description, application_name):
    """
    Checks ``value`` has type in ``types``.

    :param value: Value whose type is to be checked
    :param mixed types: A single type or tuple of types that value can be.
    :param str description: Description of expected type.
    :param application_name unicode: Name of application whose config
        contains ``value``.

    :raises ConfigurationError: If ``value`` is not of type in ``types``.
    """
    if not isinstance(value, types):
        raise ConfigurationError(
            "Application '{application_name}' has a config "
            "error. {description}; got type '{type}'.".format(
                application_name=application_name,
                description=description,
                type=type(value).__name__,
            ))


def parse_storage_string(value):
    """
    Converts a string representing a quantity and a unit identifier in to
    an integer value representing the number of bytes in that quantity, e.g.
    an input of "1G" is parsed to 1073741824. Raises ``ValueError`` if
    value cannot be converted.

    An int is always returned, so conversions resulting in a floating-point
    are always rounded UP to ensure sufficient bytes for the specified storage
    size, e.g. input of "2.1M" is converted to 2202010 bytes, not 2202009.

    :param StringTypes value: The string value to convert to integer bytes.

    :returns: ``int`` representing the supplied value converted to bytes, e.g.
        input of "2G" (2 gigabytes) returns 2147483648.
    """
    byte_multipliers = {
        'K': 1024, 'M': 1048576,
        'G': 1073741824, 'T': 1099511627776
    }
    if not isinstance(value, types.StringTypes):
        raise ValueError("Value must be string, got {type}.".format(
            type=type(value).__name__))
    pattern = re.compile("^(\d+\.?\d*)(K|M|G|T)?$", re.I | re.U)
    parsed = pattern.match(value)
    if not parsed:
        raise ValueError(
            "Value '{value}' could not be parsed as a storage quantity.".
            format(value=value)
        )
    quantity, unit = parsed.groups()
    quantity = float(quantity)
    if unit is not None:
        unit = unit.upper()
        quantity = quantity * byte_multipliers[unit]
    quantity = int(math.ceil(quantity))
    return quantity


class ApplicationMarshaller(object):
    """
    Convert ``Application`` instances or their properties to a ``dict``
    representation that matches the format of Flocker's YAML application
    configuration language.
    """
    _application = None

    def __init__(self, application):
        """
        Initialise the marshaller for a single application.

        :param application: An ``Application`` instance.
        """
        self._application = application

    def convert(self):
        """
        Convert all the properties of an ``Application`` instance to a
        ``dict`` representing a single application entry in Flocker's
        application configuration YAML format.

        :returns: A ``dict`` containing the application's converted properties.
        """
        config = dict()
        config['image'] = self.convert_image()
        ports = self.convert_ports()
        if ports:
            config['ports'] = ports
        links = self.convert_links()
        if links:
            config['links'] = links
        environment = self.convert_environment()
        if environment:
            config['environment'] = environment
        volume = self.convert_volume()
        if volume:
            config['volume'] = volume
        return config
<commit_msg>Something to convert IrestartPolicy to Flocker configuration.<commit_after># Copyright Hybrid Logic Ltd.  See LICENSE file for details.
# -*- test-case-name: flocker.node.test.test_config -*-

"""
APIs for parsing and validating configuration.
"""

from __future__ import unicode_literals, absolute_import

import math
import os
import re
import types

from twisted.python.filepath import FilePath

from yaml import safe_dump
from zope.interface import Interface, implementer

from ._model import (
    Application, AttachedVolume, Deployment, Link,
    DockerImage, Node, Port, RestartAlways, RestartNever, RestartOnFailure,
)


class IApplicationConfiguration(Interface):
    """
    A class to detect and parse an application configuration  in a given
    format, mapping configuration to a ``dict`` of keys specifying application
    names mapped to values of ``Application`` instances.
    """
    def is_valid_format():
        """
        Detect if the supplied application configuration is in a format
        compatible with this configuration parser.

        Note that "valid format" does not necessarily translate to
        "valid configuration"; this method should only indicate whether the
        supplied configuration's outermost structure is such that it should
        be treated and parsed as a configuration of this parser's format.
        Further validation should be done during the parsing stage.

        :returns: A ``bool`` indicating ``True`` for a fig-style configuration
            or ``False`` if fig-style is not detected.
        """

    def applications():
        """
        Returns the ``Application`` instances parsed from the supplied
        configuration.

        This method should only be called after valdiating the format
        with a call to ``is_valid_format``.

        This method should only be called once, in that calling it
        multiple times will re-parse an already parsed config.

        :returns: A ``dict`` mapping application names to ``Application``
            instances.
        """


class ConfigurationError(Exception):
    """
    Some part of the supplied configuration was wrong.

    The exception message will include some details about what.
    """


def _check_type(value, types, description, application_name):
    """
    Checks ``value`` has type in ``types``.

    :param value: Value whose type is to be checked
    :param mixed types: A single type or tuple of types that value can be.
    :param str description: Description of expected type.
    :param application_name unicode: Name of application whose config
        contains ``value``.

    :raises ConfigurationError: If ``value`` is not of type in ``types``.
    """
    if not isinstance(value, types):
        raise ConfigurationError(
            "Application '{application_name}' has a config "
            "error. {description}; got type '{type}'.".format(
                application_name=application_name,
                description=description,
                type=type(value).__name__,
            ))


def parse_storage_string(value):
    """
    Converts a string representing a quantity and a unit identifier in to
    an integer value representing the number of bytes in that quantity, e.g.
    an input of "1G" is parsed to 1073741824. Raises ``ValueError`` if
    value cannot be converted.

    An int is always returned, so conversions resulting in a floating-point
    are always rounded UP to ensure sufficient bytes for the specified storage
    size, e.g. input of "2.1M" is converted to 2202010 bytes, not 2202009.

    :param StringTypes value: The string value to convert to integer bytes.

    :returns: ``int`` representing the supplied value converted to bytes, e.g.
        input of "2G" (2 gigabytes) returns 2147483648.
    """
    byte_multipliers = {
        'K': 1024, 'M': 1048576,
        'G': 1073741824, 'T': 1099511627776
    }
    if not isinstance(value, types.StringTypes):
        raise ValueError("Value must be string, got {type}.".format(
            type=type(value).__name__))
    pattern = re.compile("^(\d+\.?\d*)(K|M|G|T)?$", re.I | re.U)
    parsed = pattern.match(value)
    if not parsed:
        raise ValueError(
            "Value '{value}' could not be parsed as a storage quantity.".
            format(value=value)
        )
    quantity, unit = parsed.groups()
    quantity = float(quantity)
    if unit is not None:
        unit = unit.upper()
        quantity = quantity * byte_multipliers[unit]
    quantity = int(math.ceil(quantity))
    return quantity


class ApplicationMarshaller(object):
    """
    Convert ``Application`` instances or their properties to a ``dict``
    representation that matches the format of Flocker's YAML application
    configuration language.
    """
    _application = None

    def __init__(self, application):
        """
        Initialise the marshaller for a single application.

        :param application: An ``Application`` instance.
        """
        self._application = application

    def convert(self):
        """
        Convert all the properties of an ``Application`` instance to a
        ``dict`` representing a single application entry in Flocker's
        application configuration YAML format.

        :returns: A ``dict`` containing the application's converted properties.
        """
        config = dict()
        config['image'] = self.convert_image()
        ports = self.convert_ports()
        if ports:
            config['ports'] = ports
        links = self.convert_links()
        if links:
            config['links'] = links
        environment = self.convert_environment()
        if environment:
            config['environment'] = environment
        volume = self.convert_volume()
        if volume:
            config['volume'] = volume
        restart_policy = self.convert_restart_policy()
        if restart_policy:
            config['restart_policy'] = restart_policy
        return config

    def convert_restart_policy(self):
        """
        """
        policies = {
            RestartNever: lambda policy: dict(name='never'),
        }
        policy = self._application.restart_policy
        converter = policies[policy.__class__]
        return converter(policy)

{'fraction_non_alphanumeric': 0.08549415955596057, 'fraction_numerical': 0.01209510396818822, 'mean_word_length': 2.692872438054451, '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': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1515098', 'n_tokens_mistral': 3120, 'n_tokens_neox': 2944, 'n_words': 1207}