Example #1
0
    def run(
        self,
        inputcode,
        max_iterations=None,
        run_forever=False,
        frame_limiter=False,
        verbose=False,
    ):
        if os.path.isfile(inputcode):
            source = open(inputcode).read()
            filename = inputcode
        elif isinstance(inputcode, str):
            filename = "<string>"
            source = inputcode
        else:
            raise ValueError("inputcode must be a str or file like object.")

        self._load_namespace(self._namespace, filename)
        # TODO:  The shell module (sbio) accesses the executor via its name here,
        # making this event based would remove the need for this.
        self._executor = executor = LiveExecution(
            source, ns=self._namespace, filename=filename
        )

        if run_forever is False:
            if max_iterations is None:
                max_iterations = 1

        try:
            # Iterations only increment, whereas FRAME can decrement if the user sets a negative speed.
            iteration = 0
            first_run = True
            while first_run or iteration != max_iterations:
                # Main loop:
                # - Setup bot on first run.
                # - Run draw function for if present.
                # - Process events
                # - Update state
                start_time = time()
                iteration += 1

                canvas_dirty = False
                # Reset output graphics state
                self._canvas.reset_canvas()

                with executor.run_context() as (known_good, source, ns):
                    if not known_good:
                        # New code has been loaded, but it may have errors.
                        # Setting first_run forces the global context to be re-run
                        # Which has the side effect of loading all functions and state.
                        first_run = True

                    if first_run:
                        # Run code in the global namespace, followed by setup()
                        executor.run()
                        if "setup" in executor.ns:
                            executor.ns["setup"]()

                        if "draw" in executor.ns:
                            if self._speed is None:
                                self._speed = DEFAULT_ANIMATION_SPEED

                        # Store initial state so script can revert to a known state when livecoding.
                        self._initial_namespace = copy.copy(self._namespace)
                        canvas_dirty = True

                    is_animation = "draw" in executor.ns
                    if is_animation and self._speed != 0:
                        # If speed is 0, then don't output anything..
                        executor.ns["draw"]()
                        canvas_dirty = True

                if canvas_dirty:
                    self._canvas.flush(self._frame)

                if frame_limiter:
                    # Frame limiting is only used when running the GUI.
                    if is_animation:
                        # User specifies framerate, via speed(...) or use a default.
                        fps = self._speed
                        timeout = self._calculate_frame_delay(
                            fps if fps is not None else DEFAULT_ANIMATION_SPEED,
                            start_time,
                        )
                        next_frame_due = time() + timeout
                    else:
                        # Re-run the mainloop at 30fps, so that the GUI remains responsive.
                        next_frame_due = time() + 1.0 / DEFAULT_GUI_UPDATE_SPEED
                else:
                    # Do not sleep between frames.
                    next_frame_due = time()

                # Handle events
                continue_running, first_run = self._handle_events(
                    iteration, is_animation, next_frame_due
                )
                if not continue_running:
                    # Event handler returns False if it receives a message to quit.
                    break

            # Main loop has finished, return True to indicate it exited normally.
            return True
        except Exception as e:
            # Catch Exception, not BaseException, so that KeyboardInterrupts (ctrl+c) still work.
            # if something goes wrong, print verbose system output.

            import sys

            if verbose:
                errmsg = traceback.format_exc()
            else:
                errmsg = simple_traceback(e, executor.known_good or "")
            sys.stderr.write(f"{errmsg}\n")
            return False
Example #2
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
Example #3
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, 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 = simple_traceback(e, executor.known_good or '')
            print >> sys.stderr, errmsg
            if break_on_error:
                raise