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
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", ) )
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)
def _report_current_action(self, cmd, description: str) -> None: self.send_message( BackendEvent( event_type="InlineProgress", command_id=cmd["id"], description=description, ))
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
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) )
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)
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) )
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)
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
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)
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()
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")
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")
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()
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()
def _show_error(self, text): self._response_queue.append( BackendEvent(event_type="ProgramOutput", stream_name="stderr", data="stderr"))