Exemple #1
0
    def run(self,
            inputcode,
            iterations=None,
            run_forever=False,
            frame_limiter=False,
            verbose=False,
            break_on_error=False):
        '''
        Executes the contents of a Nodebox/Shoebot script
        in current surface's context.

        :param inputcode: Path to shoebot source or string containing source
        :param iterations: None or Maximum amount of frames to run
        :param run_forever: If True then run until user quits the bot
        :param frame_limiter: If True then sleep between frames to respect speed() command.
        '''
        source = None
        filename = None

        if os.path.isfile(inputcode):
            source = open(inputcode).read()
            filename = inputcode
        elif isinstance(inputcode, str):
            filename = 'shoebot_code'
            source = inputcode

        self._load_namespace(self._namespace, filename)
        self._executor = executor = LiveExecution(source,
                                                  ns=self._namespace,
                                                  filename=filename)

        try:
            if not iterations:
                if run_forever:
                    iterations = None
                else:
                    iterations = 1
            iteration = 0

            event = None

            while iteration != iterations and not event_is(event, QUIT_EVENT):
                # do the magic

                # First iteration
                self._run_frame(executor,
                                limit=frame_limiter,
                                iteration=iteration)
                if iteration == 0:
                    self._initial_namespace = copy.copy(
                        self._namespace)  # Stored so script can be rewound
                iteration += 1

                # Subsequent iterations
                while self._should_run(iteration,
                                       iterations) and event is None:
                    iteration += 1
                    self._run_frame(executor,
                                    limit=frame_limiter,
                                    iteration=iteration)
                    event = next_event()
                    if not event:
                        self._canvas.sink.main_iteration(
                        )  # update GUI, may generate events..

                while run_forever:
                    #
                    # Running in GUI, bot has finished
                    # Either -
                    #   receive quit event and quit
                    #   receive any other event and loop (e.g. if var changed or source edited)
                    #
                    while event is None:
                        self._canvas.sink.main_iteration()
                        event = next_event(block=True, timeout=0.05)
                        if not event:
                            self._canvas.sink.main_iteration(
                            )  # update GUI, may generate events..

                    if event.type == QUIT_EVENT:
                        break
                    elif event.type == SOURCE_CHANGED_EVENT:
                        # Debounce SOURCE_CHANGED events -
                        # gedit generates two events for changing a single character -
                        # delete and then add
                        while event and event.type == SOURCE_CHANGED_EVENT:
                            event = next_event(block=True, timeout=0.001)
                    elif event.type == SET_WINDOW_TITLE:
                        self._canvas.sink.set_title(event.data)

                    event = None  # this loop is a bit weird...
                    break

        except Exception as e:
            # this makes KeyboardInterrupts still work
            # if something goes wrong, print verbose system output
            # maybe this is too verbose, but okay for now

            import sys
            if verbose:
                errmsg = traceback.format_exc()
            else:
                errmsg = simple_traceback(e, executor.known_good or '')
            print(errmsg, file=sys.stderr)
            if break_on_error:
                raise
Exemple #2
0
    def run(self, inputcode, iterations=None, run_forever=False, frame_limiter=False, verbose=False):
        '''
        Executes the contents of a Nodebox/Shoebot script
        in current surface's context.

        :param inputcode: path to shoebot file or whole source code
        :param iterations: maximum amount of frames to run
        :param run_forever: if True will run until the user quits the bot
        :param frame_limiter: Time a frame should take to run (float - seconds)
        '''
        source = None
        filename = None

        if os.path.isfile(inputcode):
            source = open(inputcode).read()
            filename = inputcode
        elif isinstance(inputcode, basestring):
            filename = 'shoebot_code'
            source = inputcode

        self._load_namespace(self._namespace, filename)
        self._executor = executor = LiveExecution(source, ns=self._namespace, filename=filename)

        try:
            if not iterations:
                if run_forever:
                    iterations = None
                else:
                    iterations = 1
            iteration = 0

            event = None

            while iteration != iterations and not event_is(event, QUIT_EVENT):
                # do the magic

                # First iteration
                self._run_frame(executor, limit=frame_limiter, iteration=iteration)
                if iteration == 0:
                    self._initial_namespace = copy.copy(self._namespace)  # Stored so script can be rewound
                iteration += 1

                # Subsequent iterations
                while self._should_run(iteration, iterations) and event is None:
                    iteration += 1
                    self._run_frame(executor, limit=frame_limiter, iteration=iteration)
                    event = next_event()
                    if not event:
                        self._canvas.sink.main_iteration()  # update GUI, may generate events..

                while run_forever:
                    #
                    # Running in GUI, bot has finished
                    # Either -
                    #   receive quit event and quit
                    #   receive any other event and loop (e.g. if var changed or source edited)
                    #
                    while event is None:
                        self._canvas.sink.main_iteration()
                        event = next_event(block=True, timeout=0.05)
                        if not event:
                            self._canvas.sink.main_iteration()  # update GUI, may generate events..

                    if event.type == QUIT_EVENT:
                        break
                    elif event.type == SOURCE_CHANGED_EVENT:
                        # Debounce SOURCE_CHANGED events -
                        # gedit generates two events for changing a single character -
                        # delete and then add
                        while event and event.type == SOURCE_CHANGED_EVENT:
                            event = next_event(block=True, timeout=0.001)
                    elif event.type == SET_WINDOW_TITLE:
                        self._canvas.sink.set_title(event.data)

                    event = None  # this loop is a bit weird...
                    break

        except Exception as e:
            # this makes KeyboardInterrupts still work
            # if something goes wrong, print verbose system output
            # maybe this is too verbose, but okay for now

            import sys
            if verbose:
                errmsg = traceback.format_exc()
            else:
                errmsg = self._simple_traceback(e, executor.known_good or '')
            print >> sys.stderr, errmsg
Exemple #3
0
    def _handle_events(self, iteration, is_animation, next_frame_due):
        """
        The Shoebot mainloop, GUI and shell communicate with each other using events.

        Examples include live variables being changed from the GUI, the shell
        or Shoebot itself, or the user quitting from the GUI.

        This handler waits for events and updates where needed, the loop also
        serves handles the delay between frames for animated bots.

        return: continue_running, restart
        """

        # Things we might want to do on returning:
        # Restart (if state has changed and not an animation).
        # Quit
        # Continue running.

        restart_bot = False
        while True:
            timeout = min(next_frame_due - time(), 0.1)
            event = next_event(
                block=timeout > 0, timeout=timeout if timeout > 0 else None
            )
            # Update GUI, which may in-turn generate new events.
            self._canvas.sink.main_iteration()

            if event is not None:
                if event.type == QUIT_EVENT:
                    # The user chose to quit via the shell or GUI.
                    return False, False
                elif event.type == REDRAW_EVENT:
                    # The GUI needs redrawing (usually because the Window was resized)
                    # TODO: This is a hack/workaround, since the graphics backend doesn't currently support redrawing
                    if not is_animation:
                        return True, True
                elif event.type == SET_WINDOW_TITLE_EVENT:
                    # A new window title was specified in the shell
                    self._canvas.sink.set_title(event.data)
                elif event.type == SOURCE_CHANGED_EVENT:
                    # New source code was loaded from the shell.
                    # Debounce SOURCE_CHANGED events -
                    # Gedit generates two events for changing a single character -
                    # delete and then add
                    while event and event.type == SOURCE_CHANGED_EVENT:
                        # TODO, can this be handled differently (non-blocking or just ignore source that is the same?)
                        event = next_event(block=True, timeout=0.001)
                    if not is_animation:
                        return True, True
                elif event.type == VARIABLE_CHANGED_EVENT:
                    # A Variable was changed, from the shell or the GUI.
                    # TODO, make VARIABLE_ADDED_EVENT, VARIABLE_DELETED_EVENT
                    # TODO, sketched out, fix up properly.
                    self._executor.ns[event.data.name] = event.data.value
                    # TODO: State was updated, bot needs to execute again ???
                    if not is_animation:
                        # On non-animated bots, updating variables re-runs the whole
                        # whole bot so that the user may see the updated state.
                        return True, True

            if time() >= next_frame_due:
                break

        if event is None:
            # event is None indicates the handler timed out.
            # If the bot is animated, then the next frame is due and
            # variables that update per-frame must be updated.

            if is_animation and self._speed is not None:
                if self._speed > 0:
                    self._frame += 1
                elif self._speed < 0:
                    self._frame -= 1
            self._update_animation_variables(iteration, self._frame)

        # By default return continue_running=True.
        return True, restart_bot