<commit_before>"""
colors.py
=========
Play with colors!
"""
import colorsys
import random as random_

__version__ = '0.0.0'
__all__ = ('Color', 'HSVColor', 'RGBColor', 'HexColor', 'ColorWheel',
           'rgb', 'hsv', 'hex', 'random',)


class _ColorMetaClass(type):
    """
    Metaclass for Color to simply map the cls.Meta.properties to getters.

    >>> RGBColor(r=150, g=0, b=100).red
    150

    """
    def __new__(cls, name, bases, attrs):
        # Check for internal Meta class providing a property map
        if 'Meta' in attrs and hasattr(attrs['Meta'], 'properties'):
            for index, prop in enumerate(attrs['Meta'].properties):
                # Assign pretty getters to each property name
                attrs[prop] = property(lambda self, index=index: self._color[index])
        return super(_ColorMetaClass, cls).__new__(cls, name, bases, attrs)


class Color(object):
    """ Abstract base class for all color types. """
    __metaclass__ = _ColorMetaClass

    @property
    def hex(self):
        """ Hex is used the same way for all types. """
        return HexColor('%02x%02x%02x' % tuple(self.rgb))

    @property
    def rgb(self):
        raise NotImplemented

    @property
    def hsv(self):
        raise NotImplemented

    def __iter__(self):
        """ Treat the color object as an iterable to iterate over color values
        Allows mapping such as:

        >>> list(rgb(100, 50, 0))
        [100, 50, 0]
        >>> for i in rgb(100, 50, 0): print i
        100
        50
        0

        """
        return iter(self._color)

    def __len__(self):
        return len(self._color)

    def __str__(self):
        return ', '.join(map(str, self._color))

    def __repr__(self):
        base = u'<%s %s>'
        properties = [
            '%s: %s' % (prop, getattr(self, prop)) \
                for prop in self.Meta.properties
        ]
        return base % (self.__class__.__name__, ', '.join(properties))


class HSVColor(Color):
    """ Hue Saturation Value """

    def __init__(self, h=0, s=0, v=0):
        self._color = h, s, v

    @property
    def rgb(self):
        return RGBColor(*map(lambda c: c * 255, colorsys.hsv_to_rgb(*self._color)))

    @property
    def hsv(self):
        return self

    class Meta:
        properties = ('hue', 'saturation', 'value')


class RGBColor(Color):
    """ Red Green Blue """

    def __init__(self, r=0, g=0, b=0):
        self._color = r, g, b

    @property
    def rgb(self):
        return self

    @property
    def hsv(self):
        return HSVColor(*colorsys.rgb_to_hsv(*map(lambda c: c / 255.0, self._color)))

    class Meta:
        properties = ('red', 'green', 'blue')


class HexColor(RGBColor):
    """ Typical 6 digit hexadecimal colors.

    Warning: accuracy is lost when converting a color to hex
    """

    def __init__(self, hex='000000'):
        if len(hex) != 6:
            raise ValueError('Hex color must be 6 digits')

        hex = hex.lower()
        for digit in hex:
            if digit not in '0123456789abcdef':
                raise ValueError('Not a valid hex number')

        self._color = hex[:2], hex[2:4], hex[4:6]

    @property
    def rgb(self):
        return RGBColor(*[int(c, 16) for c in self._color])

    @property
    def hsv(self):
        return self.rgb.hsv

    @property
    def hex(self):
        return self

    def __str__(self):
        return '%s%s%s' % self._color


class ColorWheel(object):
    """ Iterate random colors disributed relatively evenly
    around the color wheel.

    >>> from colors import ColorWheel
    >>> wheel = ColorWheel()
    >>> print '#%s' % wheel.next().hex
    #cc8b00
    >>> wheel = ColorWheel(start=0.2)
    >>> print '#%s' % wheel.next().hex
    #00cc26
    >>> print '#%s' % wheel.next().hex
    #009ecc

    """
    def __init__(self, start=0):
        self._phase = start

    def __iter__(self):
        return self

    def next(self):
        shift = (random_.random() * 0.1) + 0.1
        self._phase += shift
        if self._phase > 1:
            self._phase -= 1
        return HSVColor(self._phase, 1, 0.8)<commit_msg>Restrict values to safe ranges<commit_after>"""
colors.py
=========
Play with colors!
"""
import colorsys
import random as random_

__version__ = '0.0.0'
__all__ = ('Color', 'HSVColor', 'RGBColor', 'HexColor', 'ColorWheel',
           'rgb', 'hsv', 'hex', 'random',)


class _ColorMetaClass(type):
    """
    Metaclass for Color to simply map the cls.Meta.properties to getters.

    >>> RGBColor(r=150, g=0, b=100).red
    150

    """
    def __new__(cls, name, bases, attrs):
        # Check for internal Meta class providing a property map
        if 'Meta' in attrs and hasattr(attrs['Meta'], 'properties'):
            for index, prop in enumerate(attrs['Meta'].properties):
                # Assign pretty getters to each property name
                attrs[prop] = property(lambda self, index=index: self._color[index])
        return super(_ColorMetaClass, cls).__new__(cls, name, bases, attrs)


class Color(object):
    """ Abstract base class for all color types. """
    __metaclass__ = _ColorMetaClass

    @property
    def hex(self):
        """ Hex is used the same way for all types. """
        return HexColor('%02x%02x%02x' % tuple(self.rgb))

    @property
    def rgb(self):
        raise NotImplemented

    @property
    def hsv(self):
        raise NotImplemented

    def __iter__(self):
        """ Treat the color object as an iterable to iterate over color values
        Allows mapping such as:

        >>> list(rgb(100, 50, 0))
        [100, 50, 0]
        >>> for i in rgb(100, 50, 0): print i
        100
        50
        0

        """
        return iter(self._color)

    def __len__(self):
        return len(self._color)

    def __str__(self):
        return ', '.join(map(str, self._color))

    def __repr__(self):
        base = u'<%s %s>'
        properties = [
            '%s: %s' % (prop, getattr(self, prop)) \
                for prop in self.Meta.properties
        ]
        return base % (self.__class__.__name__, ', '.join(properties))


class HSVColor(Color):
    """ Hue Saturation Value """

    def __init__(self, h=0, s=0, v=0):
        # No values can be greater than 1
        self._color = map(lambda c: c - 1 if c >= 1 else c, (h, s, v))

    @property
    def rgb(self):
        return RGBColor(*map(lambda c: c * 255, colorsys.hsv_to_rgb(*self._color)))

    @property
    def hsv(self):
        return self

    class Meta:
        properties = ('hue', 'saturation', 'value')


class RGBColor(Color):
    """ Red Green Blue """

    def __init__(self, r=0, g=0, b=0):
        self._color = r, g, b
        for c in self._color:
            if c < 0 or c > 255:
                raise ValueError('Color values must be between 0 and 255')

    @property
    def rgb(self):
        return self

    @property
    def hsv(self):
        return HSVColor(*colorsys.rgb_to_hsv(*map(lambda c: c / 255.0, self._color)))

    class Meta:
        properties = ('red', 'green', 'blue')


class HexColor(RGBColor):
    """ Typical 6 digit hexadecimal colors.

    Warning: accuracy is lost when converting a color to hex
    """

    def __init__(self, hex='000000'):
        if len(hex) != 6:
            raise ValueError('Hex color must be 6 digits')

        hex = hex.lower()
        for digit in hex:
            if digit not in '0123456789abcdef':
                raise ValueError('Not a valid hex number')

        self._color = hex[:2], hex[2:4], hex[4:6]

    @property
    def rgb(self):
        return RGBColor(*[int(c, 16) for c in self._color])

    @property
    def hsv(self):
        return self.rgb.hsv

    @property
    def hex(self):
        return self

    def __str__(self):
        return '%s%s%s' % self._color


class ColorWheel(object):
    """ Iterate random colors disributed relatively evenly
    around the color wheel.

    >>> from colors import ColorWheel
    >>> wheel = ColorWheel()
    >>> print '#%s' % wheel.next().hex
    #cc8b00
    >>> wheel = ColorWheel(start=0.2)
    >>> print '#%s' % wheel.next().hex
    #00cc26
    >>> print '#%s' % wheel.next().hex
    #009ecc

    """
    def __init__(self, start=0):
        # A 1.1 shift is identical to 0.1
        if start >= 1:
            start -= 1
        self._phase = start

    def __iter__(self):
        return self

    def next(self):
        shift = (random_.random() * 0.1) + 0.1
        self._phase += shift
        if self._phase >= 1:
            self._phase -= 1
        return HSVColor(self._phase, 1, 0.8)
{'fraction_non_alphanumeric': 0.1336121761357035, 'fraction_numerical': 0.02614151272220286, 'mean_word_length': 2.198810850984764, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 64, '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': '4959155', 'n_tokens_mistral': 2901, 'n_tokens_neox': 2646, 'n_words': 822}