<commit_before>
import threading
import weakref


class TestRanTooLong(BaseException):
    '''
        This is thrown when the time limit has expired
        
        This exception inherits from BaseException, so if you want to catch
        it you must explicitly specify it, as a blanket except statement
        will not catch this exception.'
        
        Generally, only internal pyfrc code needs to catch this
    '''
    pass
    
class TestEnded(BaseException):
    '''
        This is thrown when the controller has been signaled to end the test
        
        This exception inherits from BaseException, so if you want to catch
        it you must explicitly specify it, as a blanket except statement
        will not catch this exception.'
        
        Generally, only internal pyfrc code needs to catch this
    '''
    pass


class TestFroze(BaseException):
    '''
        This happens when an infinite loop of some kind in one of your
        non-robot threads is detected.
    '''
    pass


class FakeTime:
    '''
        Keeps track of time for robot code being tested, and makes sure the
        DriverStation is notified that new packets are coming in.
        
        .. note:: Do not create this object, your testing code can use this
                  object to control time via the ``fake_time`` fixture
    '''

    def __init__(self):
        self._child_threads = weakref.WeakKeyDictionary()
        self._children_free_run = False
        self._children_not_running = threading.Event()
        self._freeze_detect_threshold = 250
        self.lock = threading.RLock()
    
    def initialize(self):
        '''
            Initializes fake time
        '''
        
        self.reset()
        
        # Setup driver station hooks
        import wpilib
        
        assert not hasattr(wpilib.DriverStation, 'instance')
        
        # The DS thread causes too many problems, disable it by getting
        # rid of the thread function
        wpilib.DriverStation._run = lambda _: None
        
        self._ds = wpilib.DriverStation.getInstance()
        
        # This is used to make DriverStation.waitForData() work
        self.ds_cond = _DSCondition(self, self._ds.mutex)
        self._ds.dataCond = self.ds_cond
        
        self.thread_id = threading.current_thread().ident
        return self.ds_cond

    def __time_test__(self):
        if self.time_limit is not None and self.time_limit <= self.time:
            raise TestRanTooLong()

    def _wake_children(self, timestep):
        # Subtract the timestep from the last requested times of the threads.
        # Wake them up if the requested time is in the past, and they haven't
        # already been stopped.
        waiting_on = []
        for thread, thread_info in self._child_threads.items():
            thread_info['time'] -= timestep
            if thread_info['time'] <= 0 and thread.is_alive():
                self._children_not_running.clear()
                thread_info['event'].set()  # Wake it up
                waiting_on.append(thread)
                
        # Wait for everything we woke up to sleep again.
        # Check that we did wake something up.
        if waiting_on:
            i = 0
            while not self._children_not_running.wait(0.020):
                i += 1
                if i == self._freeze_detect_threshold:
                    raise TestFroze("Waiting on %s" % waiting_on)
                
                # if this timed out, check to see if that particular
                # child died...
                for thread in waiting_on:
                    if thread.is_alive():
                        break # out of the for loop, at least one child is active
                else:
                    break # out of the while loop, everyone is dead
    
    def children_stopped(self):
        # Avoid issues with keys disappearing from weakref dict
        keys = list(self._child_threads.keys())
        for thread in keys:
            if thread.is_alive():
                return False
        return True

    def teardown(self):
        self._children_free_run = True  # Stop any threads being blocked
        self._children_not_running.set()  # Main thread needs to be running
        for thread_info in self._child_threads.values():
            thread_info['event'].set()

    def reset(self):
        '''
            Resets the fake time to zero, and sets the time limit to default
        '''
        self.time = 0
        self.time_limit = 500
        self.in_increment = False

        # Drop references to any child threads
        self._child_threads = weakref.WeakKeyDictionary()
        self._children_not_running.set()
        self._children_free_run = False

        self.next_ds_time = 0.020

    def get(self):
        '''
            :returns: The current time for the robot
        '''
        with self.lock:
            return self.time
        
    def increment_time_by(self, time):
        '''
            Increments time by some number of seconds
            
            :param time: Number of seconds to increment time by
            :type time: float
        '''
        # If it is a thread calling us, we intercept the call and insert
        # a blocking call to a threading.Event.wait() to force it to sleep
        # in the "real world", otherwise it keeps looping indeterminately.
        # Store the requested time, and at each DS step wake up those that
        # should have fired in the previous timestep.
        current_thread = threading.current_thread()
        if current_thread.ident != self.thread_id:
            with self.lock:
                child_id = current_thread.ident
                if child_id not in self._child_threads:
                    event = threading.Event()
                    self._child_threads[current_thread] = {'event': event,
                                                           'time': time}
                child_info = self._child_threads[current_thread]
            if time > 0 and not self._children_free_run:
                # Daughter thread needs to fire in the next DS time step,
                # so make it wait
                child_info['event'].clear()
                child_info['time'] = time
                # Check to see if the other threads have finished
                running = False
                for v in self._child_threads.values():
                    if v['event'].is_set():
                        running = True
                if not running:
                    self._children_not_running.set()
                child_info['event'].wait()
            # We don't need to do anything else for children
            return

        if time < 0:
            time = 0
        
        with self.lock:
            if self.in_increment:
                raise ValueError("increment_time_by is not reentrant (did you call timer.delay?)")
            
            next_ds = self.next_ds_time - self.time 
            
        # When we wake up the TimerTasks, we can't do it while we have the lock
        # because some tasks need to get the time themselves
        # eg feeding motor watchdogs

        # This is terrible, but it works
        while time > 0:
            
            # Short wait, just get it done and exit
            if time < next_ds:
                with self.lock:<commit_msg>Avoid 'dictionary changed size during iteration' bugs in fake_time<commit_after>
import threading
import weakref


class TestRanTooLong(BaseException):
    '''
        This is thrown when the time limit has expired
        
        This exception inherits from BaseException, so if you want to catch
        it you must explicitly specify it, as a blanket except statement
        will not catch this exception.'
        
        Generally, only internal pyfrc code needs to catch this
    '''
    pass
    
class TestEnded(BaseException):
    '''
        This is thrown when the controller has been signaled to end the test
        
        This exception inherits from BaseException, so if you want to catch
        it you must explicitly specify it, as a blanket except statement
        will not catch this exception.'
        
        Generally, only internal pyfrc code needs to catch this
    '''
    pass


class TestFroze(BaseException):
    '''
        This happens when an infinite loop of some kind in one of your
        non-robot threads is detected.
    '''
    pass


class FakeTime:
    '''
        Keeps track of time for robot code being tested, and makes sure the
        DriverStation is notified that new packets are coming in.
        
        .. note:: Do not create this object, your testing code can use this
                  object to control time via the ``fake_time`` fixture
    '''

    def __init__(self):
        # Note: when iterating this list, make copies or you'll run into errors
        self._child_threads = weakref.WeakKeyDictionary()
        self._children_free_run = False
        self._children_not_running = threading.Event()
        self._freeze_detect_threshold = 250
        self.lock = threading.RLock()
    
    def initialize(self):
        '''
            Initializes fake time
        '''
        
        self.reset()
        
        # Setup driver station hooks
        import wpilib
        
        assert not hasattr(wpilib.DriverStation, 'instance')
        
        # The DS thread causes too many problems, disable it by getting
        # rid of the thread function
        wpilib.DriverStation._run = lambda _: None
        
        self._ds = wpilib.DriverStation.getInstance()
        
        # This is used to make DriverStation.waitForData() work
        self.ds_cond = _DSCondition(self, self._ds.mutex)
        self._ds.dataCond = self.ds_cond
        
        self.thread_id = threading.current_thread().ident
        return self.ds_cond

    def __time_test__(self):
        if self.time_limit is not None and self.time_limit <= self.time:
            raise TestRanTooLong()

    def _wake_children(self, timestep):
        # Subtract the timestep from the last requested times of the threads.
        # Wake them up if the requested time is in the past, and they haven't
        # already been stopped.
        waiting_on = []
        child_threads = list(self._child_threads.items())
        for thread, thread_info in child_threads:
            thread_info['time'] -= timestep
            if thread_info['time'] <= 0 and thread.is_alive():
                self._children_not_running.clear()
                thread_info['event'].set()  # Wake it up
                waiting_on.append(thread)
                
        # Wait for everything we woke up to sleep again.
        # Check that we did wake something up.
        if waiting_on:
            i = 0
            while not self._children_not_running.wait(0.020):
                i += 1
                if i == self._freeze_detect_threshold:
                    raise TestFroze("Waiting on %s" % waiting_on)
                
                # if this timed out, check to see if that particular
                # child died...
                for thread in waiting_on:
                    if thread.is_alive():
                        break # out of the for loop, at least one child is active
                else:
                    break # out of the while loop, everyone is dead
    
    def children_stopped(self):
        keys = list(self._child_threads.keys())
        for thread in keys:
            if thread.is_alive():
                return False
        return True

    def teardown(self):
        self._children_free_run = True  # Stop any threads being blocked
        self._children_not_running.set()  # Main thread needs to be running
        thread_infos = list(self._child_threads.values())
        for thread_info in thread_infos:
            thread_info['event'].set()

    def reset(self):
        '''
            Resets the fake time to zero, and sets the time limit to default
        '''
        self.time = 0
        self.time_limit = 500
        self.in_increment = False

        # Drop references to any child threads
        self._child_threads = weakref.WeakKeyDictionary()
        self._children_not_running.set()
        self._children_free_run = False

        self.next_ds_time = 0.020

    def get(self):
        '''
            :returns: The current time for the robot
        '''
        with self.lock:
            return self.time
        
    def increment_time_by(self, time):
        '''
            Increments time by some number of seconds
            
            :param time: Number of seconds to increment time by
            :type time: float
        '''
        # If it is a thread calling us, we intercept the call and insert
        # a blocking call to a threading.Event.wait() to force it to sleep
        # in the "real world", otherwise it keeps looping indeterminately.
        # Store the requested time, and at each DS step wake up those that
        # should have fired in the previous timestep.
        current_thread = threading.current_thread()
        if current_thread.ident != self.thread_id:
            with self.lock:
                child_id = current_thread.ident
                if child_id not in self._child_threads:
                    event = threading.Event()
                    self._child_threads[current_thread] = {'event': event,
                                                           'time': time}
                child_info = self._child_threads[current_thread]
            if time > 0 and not self._children_free_run:
                # Daughter thread needs to fire in the next DS time step,
                # so make it wait
                child_info['event'].clear()
                child_info['time'] = time
                # Check to see if the other threads have finished
                running = False
                child_threads = list(self._child_threads.values())
                for v in child_threads:
                    if v['event'].is_set():
                        running = True
                if not running:
                    self._children_not_running.set()
                child_info['event'].wait()
            # We don't need to do anything else for children
            return

        if time < 0:
            time = 0
        
        with self.lock:
            if self.in_increment:
                raise ValueError("increment_time_by is not reentrant (did you call timer.delay?)")
            
            next_ds = self.next_ds_time - self.time 
            
        # When we wake up the TimerTasks, we can't do it while we have the lock
        # because some tasks need to get the time themselves
        # eg feeding motor watchdogs

        # This is terrible, but it works
        while time > 0:
            
            # Short wait, just get it done and exit
            if time < next_ds:
                with self.lock:
{'fraction_non_alphanumeric': 0.06378284415323929, 'fraction_numerical': 0.002941766397004747, 'mean_word_length': 1.6691648822269807, 'pattern_counts': {'":': 0, '<': 11, '<?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': '3205256', 'n_tokens_mistral': 3815, 'n_tokens_neox': 3654, 'n_words': 1389}