<commit_before>__author__ = 'calvin'

__author__ = 'calvin'

from time import time
import threading
import weakref
from clock import Clock


class ScheduledEvent(object):
    """ Creates a trigger to the scheduler generator that is thread-safe."""
    objs = weakref.WeakValueDictionary({})
    RUNNING = 1
    KILL = 0

    def __init__(self, func, timeout=0):
        self.func = func
        self.t0 = time()
        self.timeout = timeout
        self.lock = threading.Lock()
        self._active = 1
        ScheduledEvent.clock = Clock.get_running_clock()

    def __iter__(self):
        return self

    def stop(self):
        """
        Stops the scheduled event from being called.
        """
        self._active = 0

    def start(self):
        """
        Allows the scheduled event from being called again.
        """
        self._active = 1
        self.t0 = time()
        if self.next not in self.clock.scheduled_funcs:
            self.clock.scheduled_funcs[self.next] += 1
            self.clock.queue.append(self.next)

    def kill(self):
        """
        Send a kill signal to the generator, kicking it out of it's while loop and closing the generator.
        We must catch the StopIteration exception so that the main loop does not fail.
        """

        def _kill():
            try:
                self.generator.send(ScheduledEvent.KILL)
            except StopIteration:
                pass
        # We need to schedule the kill, in case it is being called from within the function/generator
        self.clock.schedule_event(_kill)

    def reset_timer(self):
        """
        Reset the time reference, delaying any scheduled events (schedule_once, schedule_interval).
        """
        self.t0 = time()

        # schedule the call to the generator, ensuring only one function is added to the queue
        if not self.clock.scheduled_funcs[self.next]:
            self.clock.scheduled_funcs[self.next] += 1
            self.clock.queue.append(self.next)

    def __repr__(self):
        return "ScheduledEvent for {}".format(self.func)

    def next(self, *args):
        try:
            with self.lock:
                self.generator.send(ScheduledEvent.RUNNING)
        except StopIteration:
            pass

    @staticmethod
    def schedule_once(func, timeout=0, start=True):
        """
        Schedule a function to be called `interval` seconds later.
        :param func: Scheduled Function
        :param interval: Time interval in seconds
        """
        if timeout:
            s = ScheduledEvent(func, timeout)
            s.generator = s._timeout_generator(func)
            s.generator.next()
            s.start() if start else s.stop()
            return s
        else:
            ScheduledEvent.clock.scheduled_funcs[func] += 1
            ScheduledEvent.clock.queue.append(func)

    @staticmethod
    def create_trigger(func):
        """
        Create a trigger that schedules a function to be called on the next cycle of the main loop.
        Calling the trigger more than once will not schedule the function multiple times.
        :param func: Scheduled Function
        """
        s = ScheduledEvent(func, timeout=0)
        s.generator = s._trigger_generator(func)
        s.generator.next()
        return s

    @staticmethod
    def schedule_interval(func, interval, start=False):
        """
        Schedule a function to be called every `interval` seconds. Must call start() to activate.
        :param func: Scheduled Function
        :param start: start right away.
        :param interval: Time interval in seconds
        """
        s = ScheduledEvent(func, timeout=interval)
        s.generator = s._interval_generator(func)
        s.generator.next()
        s.start() if start else s.stop()
        ScheduledEvent.objs[id(s)] = s
        return s

    """
    Generators for the different types of ScheduledEvents
    """

    def _interval_generator(self, f):
        """
        Generator. The function f is called every `timeout` number of seconds.
        """
        interval = self.timeout
        scheduled_funcs = self.clock.scheduled_funcs
        append = self.clock.queue.append
        _next = self.next
        running = yield
        while running:
            t = time()
            dt = t - self.t0
            if dt > interval and self._active:
                # If we have past the timeout time, call the function, reset the reference time (t0)
                f()
                self.t0 = t
            # Add another call to this generator to the scheduled functions
            if not scheduled_funcs[_next]:
                scheduled_funcs[_next] += 1
                append(_next)
            running = yield
        # When the loop breaks, we still have one scheduled call to the generator.
        yield

    def _timeout_generator(self, f):
        """
        Generator. The function f is called after `timeout` number of seconds
        """
        timeout = self.timeout
        scheduled_funcs = self.clock.scheduled_funcs
        append = self.clock.queue.append
        _next = self.next
        running = yield
        while running:
            dt = time() - self.t0
            if dt > timeout and self._active:
                # If we have pasted the timeout time, call the function
                f()
                running = yield
            else:
                # Add another call to this generator to the scheduled functions
                if not scheduled_funcs[_next]:
                    scheduled_funcs[_next] += 1
                    append(_next)
                running = yield
        # When the loop breaks, we still have one scheduled call to the generator.
        yield

    def _trigger_generator(self, f):
        """
        Generator. The function f is called on the next Clock cycle. A function can be scheduled at most once per
        clock cycle.
        """
        scheduled_funcs = self.clock.scheduled_funcs
        append = self.clock.queue.append
        running = yield
        while running:
            if not scheduled_funcs[f] and self._active:
                scheduled_funcs[f] += 1
                append(f)
                running = yield
            else:
                running = yield

<commit_msg>added reset_trigger() method and is_scheduled property to ScheduledEvent<commit_after>__author__ = 'calvin'

__author__ = 'calvin'

from time import time
import threading
import weakref
from clock import Clock


class ScheduledEvent(object):
    """ Creates a trigger to the scheduler generator that is thread-safe."""
    objs = weakref.WeakValueDictionary({})
    RUNNING = 1
    KILL = 0

    def __init__(self, func, timeout=0):
        self.func = func
        self.t0 = time()
        self.timeout = timeout
        self.lock = threading.Lock()
        self._active = 1
        ScheduledEvent.clock = Clock.get_running_clock()

    def __iter__(self):
        return self

    def stop(self):
        """
        Stops the scheduled event from being called.
        """
        self._active = 0

    def start(self):
        """
        Allows the scheduled event from being called again.
        """
        self._active = 1
        self.t0 = time()
        if self.next not in self.clock.scheduled_funcs:
            self.clock.scheduled_funcs[self.next] += 1
            self.clock.queue.append(self.next)

    def kill(self):
        """
        Send a kill signal to the generator, kicking it out of it's while loop and closing the generator.
        We must catch the StopIteration exception so that the main loop does not fail.
        """

        def _kill():
            try:
                self.generator.send(ScheduledEvent.KILL)
            except StopIteration:
                pass
        # We need to schedule the kill, in case it is being called from within the function/generator
        self.clock.schedule_event(_kill)

    def reset_timer(self):
        """
        Reset the time reference, delaying any scheduled events (schedule_once, schedule_interval).
        """
        self.t0 = time()

        # schedule the call to the generator, ensuring only one function is added to the queue
        if not self.clock.scheduled_funcs[self.next]:
            self.clock.scheduled_funcs[self.next] += 1
            self.clock.queue.append(self.next)

    def reset_trigger(self, reschedule=False):
        if self.clock.scheduled_funcs[self.func]:
            self.clock.scheduled_funcs[self.func] -= 1
            self.clock.queue.remove(self.func)
        if reschedule:
            self.next()

    @property
    def is_scheduled(self):
        return bool(self.clock.scheduled_funcs[self.func])

    def __repr__(self):
        return "ScheduledEvent for {}{}".format(self.func, ' (scheduled)' if self.is_scheduled else '')

    def next(self, *args):
        try:
            with self.lock:
                self.generator.send(ScheduledEvent.RUNNING)
        except StopIteration:
            pass

    @staticmethod
    def schedule_once(func, timeout=0, start=True):
        """
        Schedule a function to be called `interval` seconds later.
        :param func: Scheduled Function
        :param interval: Time interval in seconds
        """
        if timeout:
            s = ScheduledEvent(func, timeout)
            s.generator = s._timeout_generator(func)
            s.generator.next()
            s.start() if start else s.stop()
            return s
        else:
            ScheduledEvent.clock.scheduled_funcs[func] += 1
            ScheduledEvent.clock.queue.append(func)

    @staticmethod
    def create_trigger(func):
        """
        Create a trigger that schedules a function to be called on the next cycle of the main loop.
        Calling the trigger more than once will not schedule the function multiple times.
        :param func: Scheduled Function
        """
        s = ScheduledEvent(func, timeout=0)
        s.generator = s._trigger_generator(func)
        s.generator.next()
        return s

    @staticmethod
    def schedule_interval(func, interval, start=False):
        """
        Schedule a function to be called every `interval` seconds. Must call start() to activate.
        :param func: Scheduled Function
        :param start: start right away.
        :param interval: Time interval in seconds
        """
        s = ScheduledEvent(func, timeout=interval)
        s.generator = s._interval_generator(func)
        s.generator.next()
        s.start() if start else s.stop()
        ScheduledEvent.objs[id(s)] = s
        return s

    """
    Generators for the different types of ScheduledEvents
    """

    def _interval_generator(self, f):
        """
        Generator. The function f is called every `timeout` number of seconds.
        """
        interval = self.timeout
        scheduled_funcs = self.clock.scheduled_funcs
        append = self.clock.queue.append
        _next = self.next
        running = yield
        while running:
            t = time()
            dt = t - self.t0
            if dt > interval and self._active:
                # If we have past the timeout time, call the function, reset the reference time (t0)
                f()
                self.t0 = t
            # Add another call to this generator to the scheduled functions
            if not scheduled_funcs[_next]:
                scheduled_funcs[_next] += 1
                append(_next)
            running = yield
        # When the loop breaks, we still have one scheduled call to the generator.
        yield

    def _timeout_generator(self, f):
        """
        Generator. The function f is called after `timeout` number of seconds
        """
        timeout = self.timeout
        scheduled_funcs = self.clock.scheduled_funcs
        append = self.clock.queue.append
        _next = self.next
        running = yield
        while running:
            dt = time() - self.t0
            if dt > timeout and self._active:
                # If we have pasted the timeout time, call the function
                f()
                running = yield
            else:
                # Add another call to this generator to the scheduled functions
                if not scheduled_funcs[_next]:
                    scheduled_funcs[_next] += 1
                    append(_next)
                running = yield
        # When the loop breaks, we still have one scheduled call to the generator.
        yield

    def _trigger_generator(self, f):
        """
        Generator. The function f is called on the next Clock cycle. A function can be scheduled at most once per
        clock cycle.
        """
        scheduled_funcs = self.clock.scheduled_funcs
        append = self.clock.queue.append
        running = yield
        while running:
            if not scheduled_funcs[f] and self._active:
                scheduled_funcs[f] += 1
                append(f)
                running = yield
            else:
                running = yield
{'fraction_non_alphanumeric': 0.07810460026111665, 'fraction_numerical': 0.0033023577298210583, 'mean_word_length': 1.8327169893408746, 'pattern_counts': {'":': 0, '<': 3, '<?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': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '106226', 'n_tokens_mistral': 3429, 'n_tokens_neox': 3321, 'n_words': 1133}