Beispiel #1
0
    def _listen_stdout(self, stdout):
        # debug("... started listening to stdout")
        # will be called from separate thread

        # allow self._response_queue to be replaced while processing
        message_queue = self._response_queue

        def publish_as_msg(data):
            msg = parse_message(data)
            if "cwd" in msg:
                self.cwd = msg["cwd"]
            message_queue.append(msg)

            if len(message_queue) > 10:
                # Probably backend runs an infinite/long print loop.
                # Throttle message throughput in order to keep GUI thread responsive.
                while len(message_queue) > 0:
                    sleep(0.005)

        while True:
            try:
                data = read_one_incoming_message_str(stdout.readline)
            except IOError:
                sleep(0.1)
                continue

            # debug("... read some stdout data", repr(data))
            if data == "":
                break
            else:
                try:
                    publish_as_msg(data)
                except Exception:
                    # Can mean the line was from subprocess,
                    # which can't be captured by stream faking.
                    # NB! If subprocess printed it without linebreak,
                    # then the suffix can be thonny message

                    parts = data.rsplit(common.MESSAGE_MARKER, maxsplit=1)

                    # print first part as it is
                    message_queue.append(
                        BackendEvent("ProgramOutput", data=parts[0], stream_name="stdout")
                    )

                    if len(parts) == 2:
                        second_part = common.MESSAGE_MARKER + parts[1]
                        try:
                            publish_as_msg(second_part)
                        except Exception:
                            # just print ...
                            message_queue.append(
                                BackendEvent(
                                    "ProgramOutput", data=second_part, stream_name="stdout"
                                )
                            )

        self._terminated_readers += 1
Beispiel #2
0
    def _listen_stdout(self):
        # debug("... started listening to stdout")
        # will be called from separate thread

        message_queue = self._message_queue

        def publish_as_msg(data):
            msg = parse_message(data)
            if "cwd" in msg:
                self.cwd = msg["cwd"]
            message_queue.append(msg)

            while len(message_queue) > 100:
                # Probably backend runs an infinite/long print loop.
                # Throttle message thougput in order to keep GUI thread responsive.
                sleep(0.1)

        while self._proc is not None:
            data = self._proc.stdout.readline()
            # debug("... read some stdout data", repr(data))
            if data == "":
                break
            else:
                try:
                    publish_as_msg(data)
                except Exception:
                    traceback.print_exc()
                    # Can mean the line was from subprocess,
                    # which can't be captured by stream faking.
                    # NB! If subprocess printed it without linebreak,
                    # then the suffix can be thonny message

                    parts = data.rsplit(common.MESSAGE_MARKER, maxsplit=1)

                    # print first part as it is
                    message_queue.append(
                        BackendEvent(
                            "ProgramOutput", data=parts[0], stream_name="stdout"
                        )
                    )

                    if len(parts) == 2:
                        second_part = common.MESSAGE_MARKER + parts[1]
                        try:
                            publish_as_msg(second_part)
                        except Exception:
                            # just print ...
                            message_queue.append(
                                BackendEvent(
                                    "ProgramOutput",
                                    data=second_part,
                                    stream_name="stdout",
                                )
                            )
Beispiel #3
0
    def _send_output(self, data, stream_name):
        if not data:
            return

        data = self._transform_output(data, stream_name)
        msg = BackendEvent(event_type="ProgramOutput", stream_name=stream_name, data=data)
        self.send_message(msg)
Beispiel #4
0
 def _report_current_action(self, cmd, description: str) -> None:
     self.send_message(
         BackendEvent(
             event_type="InlineProgress",
             command_id=cmd["id"],
             description=description,
         ))
Beispiel #5
0
 def _send_output(self, data, stream_name, tags=()):
     if not data:
         return
     msg = BackendEvent(event_type="ProgramOutput",
                        stream_name=stream_name,
                        data=data,
                        tags=tags)
     self.send_message(msg)
def on_configure(event):
    global _last_pos, _notification_is_sent
    pos = event.x, event.y
    if pos != _last_pos:
        get_backend().set_option(_LAST_POS_SETTING, pos)

    if not _notification_is_sent:
        get_backend().send_message(BackendEvent("UserWindowAppeared"))
        _notification_is_sent = True
Beispiel #7
0
 def _listen_stderr(self, stderr):
     # stderr is used only for debugger debugging
     while self.process_is_alive():
         data = stderr.readline()
         if data == "":
             break
         else:
             self._response_queue.append(
                 BackendEvent("ProgramOutput", stream_name="stderr", data=data)
             )
Beispiel #8
0
    def _send_output(self, data, stream_name):
        if not data:
            return

        if isinstance(data, bytes):
            data = data.decode(ENCODING, errors="replace")

        data = self._transform_output(data)
        msg = BackendEvent(event_type="ProgramOutput", stream_name=stream_name, data=data)
        self.send_message(msg)
Beispiel #9
0
 def _listen_stderr(self):
     # stderr is used only for debugger debugging
     while True:
         data = self._proc.stderr.readline()
         if data == "":
             break
         else:
             self._message_queue.append(
                 BackendEvent("ProgramOutput", stream_name="stderr", data=data)
             )
Beispiel #10
0
    def __init__(self, args):
        try:
            self._interpreter = self._resolve_executable(args["interpreter"])
            self._connection = self._create_connection()
        except ConnectionFailedException as e:
            text = "\n" + str(e) + "\n"
            msg = BackendEvent(event_type="ProgramOutput", stream_name="stderr", data=text)
            sys.stdout.write(serialize_message(msg) + "\n")
            sys.stdout.flush()
            return

        MicroPythonBackend.__init__(self, None, args)
Beispiel #11
0
    def _listen_stderr(self, stderr):
        # stderr is used only for debugger debugging
        while True:
            data = read_one_incoming_message_str(stderr.readline)
            if data == "":
                break
            else:
                self._response_queue.append(
                    BackendEvent("ProgramOutput", stream_name="stderr", data=data)
                )

        self._terminated_readers += 1
Beispiel #12
0
    def __init__(self, mp_executable, api_stubs_path, cwd=None):
        try:
            self._mp_executable = self._resolve_executable(mp_executable)
            self._connection = self._create_connection()
        except ConnectionFailedException as e:
            text = "\n" + str(e) + "\n"
            msg = BackendEvent(event_type="ProgramOutput",
                               stream_name="stderr",
                               data=text)
            sys.stdout.write(serialize_message(msg) + "\n")
            sys.stdout.flush()
            return

        super().__init__(None, api_stubs_path, cwd=cwd)
Beispiel #13
0
    def _report_progress(self, cmd, description: Optional[str], value: float,
                         maximum: float) -> None:
        # Don't notify too often (unless it's the final notification)
        if value != maximum and time.time(
        ) - self._last_progress_reporting_time < 0.2:
            return

        self.send_message(
            BackendEvent(
                event_type="InlineProgress",
                command_id=cmd["id"],
                value=value,
                maximum=maximum,
                description=description,
            ))
        self._last_progress_reporting_time = time.time()
Beispiel #14
0
    def __init__(self, clean, args):
        logger.info("Initializing MicroPythonBackend of type %s",
                    type(self).__name__)
        self._connection: MicroPythonConnection
        self._args = args
        self._last_interrupt_time = None
        self._local_cwd = None
        self._cwd = args.get("cwd")
        self._progress_times = {}
        self._welcome_text = None
        self._sys_path = None
        self._epoch_year = None
        self._builtin_modules = []
        self._number_of_interrupts_sent = 0

        self._builtins_info = self._fetch_builtins_info()

        MainBackend.__init__(self)
        try:
            report_time("before prepare")
            self._process_until_initial_prompt(
                interrupt=args["interrupt_on_connect"] or clean, clean=clean)
            if self._welcome_text is None:
                self._welcome_text = self._fetch_welcome_text()
                report_time("got welcome")

            # Get rid of the welcome text which was printed while searching for prompt
            self.send_message(
                BackendEvent(event_type="HideTrailingOutput",
                             text=self._welcome_text))

            self._prepare_after_soft_reboot(clean)

            if not self._builtin_modules:
                self._builtin_modules = self._fetch_builtin_modules()
                logger.debug("Built-in modules: %s", self._builtin_modules)

            self._prepare_rtc()
            self._send_ready_message()
            report_time("sent ready")
            self.mainloop()
        except ConnectionError as e:
            self._on_connection_error(e)
        except Exception:
            logger.exception("Exception in MicroPython main method")
            self._report_internal_exception("Internal error")
Beispiel #15
0
    def _cmd_Run(self, cmd):
        self._connection.close()
        self._report_time("befconn")
        args = cmd.args
        if cmd.source and args[0] == "-c":
            if len(args) > 1:
                self._send_error_message(
                    "Warning: MicroPython doesn't allow program arguments (%s) together with '-c'"
                    % " ".join(map(shlex.quote, args[1:])))
            args = ["-c", cmd.source]

        self._connection = self._create_connection(args)
        self._report_time("afconn")
        self._forward_output_until_active_prompt(self._send_output, "stdout")
        self._report_time("afforv")
        self.send_message(
            BackendEvent(event_type="HideTrailingOutput",
                         text=self._original_welcome_text))
        self._report_time("beffhelp")
        self._prepare_after_soft_reboot()
        self._report_time("affhelp")
Beispiel #16
0
    def _check_send_inline_progress(self, cmd, value, maximum, description=None):
        assert "id" in cmd
        prev_time = self._progress_times.get(cmd["id"], 0)
        if value != maximum and time.time() - prev_time < 0.2:
            # Don't notify too often
            return
        else:
            self._progress_times[cmd["id"]] = time.time()

        if description is None:
            description = cmd.get("description", "Working...")

        self.send_message(
            BackendEvent(
                event_type="InlineProgress",
                command_id=cmd["id"],
                value=value,
                maximum=maximum,
                description=description,
            )
        )
        elif args["port"] == "webrepl":

            connection = WebReplConnection(args["url"], args["password"])
        else:
            from thonny.plugins.micropython.serial_connection import (
                DifficultSerialConnection,
                SerialConnection,
            )

            connection = SerialConnection(args["port"], BAUDRATE)
            # connection = DifficultSerialConnection(args["port"], BAUDRATE)

        if "circuitpython" in args.get("proxy_class", "").lower():
            from thonny.plugins.circuitpython.cp_backend import CircuitPythonBackend

            backend = CircuitPythonBackend(connection,
                                           clean=args["clean"],
                                           args=args)
        else:
            backend = BareMetalMicroPythonBackend(connection,
                                                  clean=args["clean"],
                                                  args=args)

    except ConnectionFailedException as e:
        text = "\n" + str(e) + "\n"
        msg = BackendEvent(event_type="ProgramOutput",
                           stream_name="stderr",
                           data=text)
        sys.stdout.write(serialize_message(msg) + "\n")
        sys.stdout.flush()
Beispiel #18
0
    def _generic_read(self, method, original_limit):
        if original_limit is None:
            effective_limit = -1
        elif method == "readlines" and original_limit > -1:
            # NB! size hint is defined in weird way
            # "no more lines will be read if the total size (in bytes/characters)
            # of all lines so far **exceeds** the hint".
            effective_limit = original_limit + 1
        else:
            effective_limit = original_limit

        try:
            self._backend._enter_io_function()
            while True:
                if effective_limit == 0:
                    result = ""
                    break

                elif effective_limit > 0 and len(
                        self._buffer) >= effective_limit:
                    result = self._buffer[:effective_limit]
                    self._buffer = self._buffer[effective_limit:]
                    if method == "readlines" and not result.endswith(
                            "\n") and "\n" in self._buffer:
                        # limit is just a hint
                        # https://docs.python.org/3/library/io.html#io.IOBase.readlines
                        extra = self._buffer[:self._buffer.find("\n") + 1]
                        result += extra
                        self._buffer = self._buffer[len(extra):]
                    break

                elif method == "readline" and "\n" in self._buffer:
                    pos = self._buffer.find("\n") + 1
                    result = self._buffer[:pos]
                    self._buffer = self._buffer[pos:]
                    break

                elif self._eof:
                    result = self._buffer
                    self._buffer = ""
                    self._eof = False  # That's how official implementation does
                    break

                else:
                    self._backend.send_message(
                        BackendEvent("InputRequest",
                                     method=method,
                                     limit=original_limit))
                    msg = self._backend._fetch_next_incoming_message()
                    if isinstance(msg, InputSubmission):
                        self._buffer += msg.data
                        self._processed_symbol_count += len(msg.data)
                    elif isinstance(msg, EOFCommand):
                        self._eof = True
                    elif isinstance(msg, InlineCommand):
                        self._backend._handle_normal_command(msg)
                    else:
                        raise RuntimeError(
                            "Wrong type of command (%r) when waiting for input"
                            % (msg, ))

            return result

        finally:
            self._backend._exit_io_function()
Beispiel #19
0
 def _show_error(self, text):
     self._response_queue.append(
         BackendEvent(event_type="ProgramOutput",
                      stream_name="stderr",
                      data="stderr"))