<commit_before>import spyral
from spyral.sprite import Sprite, Group
from collections import defaultdict


class Animation(object):
    def __init__(self, property,
                 animator,
                 duration=1.0,
                 absolute=True,
                 shift=None,
                 loop=False
                 ):
        """
        *animator* determines the animation you wish to apply

        *duration* is the amount of time the animation should take.

        *property* is the property of the sprite you wish to animate.
        Special properties are "x" and "y" which refer to the first
        and second parts of the position tuple.
        """

        # Idea: These animators could be used for camera control
        # at some point. Everything should work pretty much the same.

        properties = ['x', 'y', 'image', 'scale', 'pos']
        if property not in properties:
            raise ValueError('%s is not a valid animation property.' % (property))
        self.property = property
        self.animator = animator
        self.duration = duration
        self.loop = loop
        self.properties = set((property,))
        self._shift = shift
        
        self.on_complete = spyral.Signal()

    def evaluate(self, sprite, progress):
        progress = progress / self.duration
        value = self.animator(sprite, progress)
        if self._shift is not None:
            if self.property == 'pos':
                value = (value[0] + self._shift[0],
                         value[1] + self._shift[1])
            else:
                value = value + self._shift
        return {self.property: value}

    def __and__(self, second):
        return MultiAnimation(self, second)

    def __iand__(self, second):
        return MultiAnimation(self, second)

    def __add__(self, second):
        return SequentialAnimation(self, second)

    def __iadd__(self, second):
        return SequentialAnimation(self, second)


class MultiAnimation(Animation):
    def __init__(self, *animations, **kwargs):
        """
        This does not respect the absolute setting on individual
        animations. Pass absolute as a keyword argument to change,
        default is True.
        Absolute applies only to numerical properties.

        loop is accepted as a kwarg, default is True if any child
        loops, or False otherwise.
        """
        self.properties = set()
        self._animations = []
        self.duration = 0
        self.absolute = kwargs.get('absolute', True)
        self.loop = False
        for animation in animations:
            i = animation.properties.intersection(self.properties)
            if i:
                raise ValueError("Cannot animate on the same properties twice: %s" % str(i))
            self.properties.update(animation.properties)
            self._animations.append(animation)
            self.duration = max(self.duration, animation.duration)
            if animation.loop:
                self.loop = True
        # Ensure we don't clobber on properties
        clobbering_animations = [('scale', {'scale_x', 'scale_y'}),
                                 ('pos', {'x', 'y', 'position'}),
                                 ('position', {'x', 'y', 'pos'})]
        for p, others in clobbering_animations:
            if p in self.properties and self.properties.intersection(others):
                raise ValueError("Cannot animate on %s and %s in the same animation." % (p, str(self.properties.intersection(others).pop())))
        self.loop = kwargs.get('loop', self.loop)
        self.on_complete = spyral.Signal()

    def evaluate(self, sprite, progress):
        res = {}
        for animation in self._animations:
            if progress <= animation.duration:
                res.update(animation.evaluate(sprite, progress))
            else:
                res.update(animation.evaluate(sprite, animation.duration))
        return res


class SequentialAnimation(Animation):
    def __init__(self, *animations, **kwargs):
        """
        An animation that represents the input animations in sequence.

        loop is accepted as a kwarg, default is False.

        If the last animation in a SequentialAnimation is set to loop,
        that animation will be looped indefinitely at the end, but not
        the entire SequentialAnimation. If loop is set to true, the
        entire SequentialAnimation will loop indefinitely.
        """
        self.properties = set()
        self._animations = animations
        self.duration = 0
        self.absolute = True
        self.loop = kwargs.get('loop', False)
        for animation in animations:
            self.properties.update(animation.properties)
            self.duration += animation.duration
            if self.loop and animation.loop:
                raise ValueError("Looping sequential animation with a looping animation anywhere in the sequence is not allowed.")
            if animation.loop and animation is not animations[-1]:
                raise ValueError("Looping animation in the middle of a sequence is not allowed.")
        if animations[-1].loop is True:
            self.loop = self.duration - animations[-1].duration
        self.on_complete = spyral.Signal()

    def evaluate(self, sprite, progress):
        res = {}
        if progress == self.duration:
            res.update(self._animations[-1].evaluate(sprite,
                       self._animations[-1].duration))
            return res
        i = 0
        while progress > self._animations[i].duration:
            progress -= self._animations[i].duration
            i += 1
        if i > 0:
            res.update(self._animations[i - 1].evaluate(sprite,
                       self._animations[i - 1].duration))
        res.update(self._animations[i].evaluate(sprite, progress))
        return res


class DelayAnimation(Animation):
    def __init__(self, duration=1.0):
        self.absolute = False
        self.properties = set([])
        self.duration = duration
        self.loop = False
        self.on_complete = spyral.Signal()

    def evaluate(self, sprite, progress):
        return {}
<commit_msg>Animations are now valid on any properties for sprites.<commit_after>import spyral
from spyral.sprite import Sprite, Group
from collections import defaultdict


class Animation(object):
    def __init__(self, property,
                 animator,
                 duration=1.0,
                 absolute=True,
                 shift=None,
                 loop=False
                 ):
        """
        *animator* determines the animation you wish to apply

        *duration* is the amount of time the animation should take.

        *property* is the property of the sprite you wish to animate.
        Special properties are "x" and "y" which refer to the first
        and second parts of the position tuple.
        """

        # Idea: These animators could be used for camera control
        # at some point. Everything should work pretty much the same.

        self.property = property
        self.animator = animator
        self.duration = duration
        self.loop = loop
        self.properties = set((property,))
        self._shift = shift
        
        self.on_complete = spyral.Signal()

    def evaluate(self, sprite, progress):
        progress = progress / self.duration
        value = self.animator(sprite, progress)
        if self._shift is not None:
            if self.property == 'pos':
                value = (value[0] + self._shift[0],
                         value[1] + self._shift[1])
            else:
                value = value + self._shift
        return {self.property: value}

    def __and__(self, second):
        return MultiAnimation(self, second)

    def __iand__(self, second):
        return MultiAnimation(self, second)

    def __add__(self, second):
        return SequentialAnimation(self, second)

    def __iadd__(self, second):
        return SequentialAnimation(self, second)


class MultiAnimation(Animation):
    def __init__(self, *animations, **kwargs):
        """
        This does not respect the absolute setting on individual
        animations. Pass absolute as a keyword argument to change,
        default is True.
        Absolute applies only to numerical properties.

        loop is accepted as a kwarg, default is True if any child
        loops, or False otherwise.
        """
        self.properties = set()
        self._animations = []
        self.duration = 0
        self.absolute = kwargs.get('absolute', True)
        self.loop = False
        for animation in animations:
            i = animation.properties.intersection(self.properties)
            if i:
                raise ValueError("Cannot animate on the same properties twice: %s" % str(i))
            self.properties.update(animation.properties)
            self._animations.append(animation)
            self.duration = max(self.duration, animation.duration)
            if animation.loop:
                self.loop = True
        # Ensure we don't clobber on properties
        clobbering_animations = [('scale', {'scale_x', 'scale_y'}),
                                 ('pos', {'x', 'y', 'position'}),
                                 ('position', {'x', 'y', 'pos'})]
        for p, others in clobbering_animations:
            if p in self.properties and self.properties.intersection(others):
                raise ValueError("Cannot animate on %s and %s in the same animation." % (p, str(self.properties.intersection(others).pop())))
        self.loop = kwargs.get('loop', self.loop)
        self.on_complete = spyral.Signal()

    def evaluate(self, sprite, progress):
        res = {}
        for animation in self._animations:
            if progress <= animation.duration:
                res.update(animation.evaluate(sprite, progress))
            else:
                res.update(animation.evaluate(sprite, animation.duration))
        return res


class SequentialAnimation(Animation):
    def __init__(self, *animations, **kwargs):
        """
        An animation that represents the input animations in sequence.

        loop is accepted as a kwarg, default is False.

        If the last animation in a SequentialAnimation is set to loop,
        that animation will be looped indefinitely at the end, but not
        the entire SequentialAnimation. If loop is set to true, the
        entire SequentialAnimation will loop indefinitely.
        """
        self.properties = set()
        self._animations = animations
        self.duration = 0
        self.absolute = True
        self.loop = kwargs.get('loop', False)
        for animation in animations:
            self.properties.update(animation.properties)
            self.duration += animation.duration
            if self.loop and animation.loop:
                raise ValueError("Looping sequential animation with a looping animation anywhere in the sequence is not allowed.")
            if animation.loop and animation is not animations[-1]:
                raise ValueError("Looping animation in the middle of a sequence is not allowed.")
        if animations[-1].loop is True:
            self.loop = self.duration - animations[-1].duration
        self.on_complete = spyral.Signal()

    def evaluate(self, sprite, progress):
        res = {}
        if progress == self.duration:
            res.update(self._animations[-1].evaluate(sprite,
                       self._animations[-1].duration))
            return res
        i = 0
        while progress > self._animations[i].duration:
            progress -= self._animations[i].duration
            i += 1
        if i > 0:
            res.update(self._animations[i - 1].evaluate(sprite,
                       self._animations[i - 1].duration))
        res.update(self._animations[i].evaluate(sprite, progress))
        return res


class DelayAnimation(Animation):
    def __init__(self, duration=1.0):
        self.absolute = False
        self.properties = set([])
        self.duration = duration
        self.loop = False
        self.on_complete = spyral.Signal()

    def evaluate(self, sprite, progress):
        return {}

{'fraction_non_alphanumeric': 0.09021569753137046, 'fraction_numerical': 0.003280570819322562, 'mean_word_length': 2.011607804396147, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, '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': '2298442', 'n_tokens_mistral': 3087, 'n_tokens_neox': 2974, 'n_words': 998}