def _cmd_get_globals(self, cmd): warnings.warn("_cmd_get_globals is deprecated for CPython") try: return InlineResponse( "get_globals", module_name=cmd.module_name, globals=self.export_globals(cmd.module_name), ) except Exception as e: return InlineResponse("get_globals", module_name=cmd.module_name, error=str(e))
def _cmd_editor_autocomplete(self, cmd): error = None try: from thonny import jedi_utils with warnings.catch_warnings(): completions = jedi_utils.get_script_completions( cmd.source, cmd.row, cmd.column, cmd.filename, sys_path=self._get_sys_path_for_analysis(), ) except ImportError: completions = [] error = "Could not import jedi" except Exception as e: completions = [] logger.info("Autocomplete error", exc_info=e) error = "Autocomplete error: " + str(e) return InlineResponse( "editor_autocomplete", source=cmd.source, row=cmd.row, column=cmd.column, filename=cmd.filename, completions=completions, error=error, )
def _cmd_get_active_distributions(self, cmd): try: dists = {} for path in self._get_library_paths(): children = self._get_dir_children_info(path) if children is None: continue for name, info in children.items(): if info["kind"] == "dir": key = name elif name.endswith(".py"): key = name[:-3] elif name.endswith(".mpy"): key = name[:-4] else: continue dists[key] = { "project_name": key, "key": key, "guessed_pypi_name": self._guess_package_pypi_name(key), "location": path, "version": "n/a", } return dict( distributions=dists, usersitepackages=None, ) except Exception: return InlineResponse("get_active_distributions", error=traceback.format_exc())
def _cmd_shell_autocomplete(self, cmd): error = None try: from thonny import jedi_utils except ImportError: completions = [] error = "Could not import jedi" else: import __main__ try: with warnings.catch_warnings(): completions = jedi_utils.get_interpreter_completions( cmd.source, [__main__.__dict__], sys_path=self._get_sys_path_for_analysis()) except Exception as e: completions = [] logger.info("Autocomplete error", exc_info=e) error = "Autocomplete error: " + str(e) return InlineResponse( "shell_autocomplete", source=cmd.source, completions=completions, error=error, row=cmd.row, column=cmd.column, )
def create_error_response(**kw): if "error" not in kw: kw["error"] = traceback.format_exc() if isinstance(cmd, ToplevelCommand): return ToplevelResponse(command_name=cmd.name, **kw) else: return InlineResponse(command_name=cmd.name, **kw)
def _cmd_get_locals(self, cmd): for frame in inspect.stack(): if id(frame) == cmd.frame_id: return InlineResponse("get_locals", locals=self.export_variables( frame.f_locals)) raise RuntimeError("Frame '{0}' not found".format(cmd.frame_id))
def _cmd_get_completion_details(self, cmd): # it is assumed this gets called after requesting editor or shell completions from thonny import jedi_utils return InlineResponse( "get_completion_details", full_name=cmd.full_name, details=jedi_utils.get_completion_details(cmd.full_name), )
def _cmd_shell_autocomplete(self, cmd): # TODO: completions = [] error = "Could not import jedi" return InlineResponse("shell_autocomplete", source=cmd.source, completions=completions, error=error)
def _cmd_write_file(self, cmd): def generate_blocks(content_bytes, block_size): for i in range(0, len(content_bytes), block_size): yield content_bytes[i : i + block_size] self._write_file(generate_blocks(cmd["content_bytes"], BUFFER_SIZE), cmd["path"]) return InlineResponse( command_name="write_file", path=cmd["path"], editor_id=cmd.get("editor_id") )
def _cmd_write_file(self, cmd): mount_name = self._get_fs_mount_name() if mount_name is not None: # CircuitPython devices only allow writing via mount, # other mounted devices may show outdated data in mount # when written via serial. self._write_file_via_mount(cmd) else: self._write_file_via_serial(cmd) return InlineResponse(command_name="write_file", path=cmd["path"], editor_id=cmd.get("editor_id"))
def _cmd_get_shell_calltip(self, cmd): from thonny import jedi_utils import __main__ signatures = jedi_utils.get_interpreter_signatures( cmd.source, [__main__.__dict__], sys_path=self._get_sys_path_for_analysis()) return InlineResponse( "get_shell_calltip", source=cmd.source, row=cmd.row, column=cmd.column, filename=cmd.filename, signatures=signatures, )
def handle_command(self, cmd): assert isinstance(cmd, (ToplevelCommand, InlineCommand)) def create_error_response(**kw): if isinstance(cmd, ToplevelCommand): return ToplevelResponse(command_name=cmd.name, **kw) else: return InlineResponse(command_name=cmd.name, **kw) handler = getattr(self, "_cmd_" + cmd.name, None) if handler is None: response = create_error_response(error="Unknown command: " + cmd.name) else: try: response = handler(cmd) except SystemExit: # Must be caused by Thonny or plugins code if isinstance(cmd, ToplevelCommand): traceback.print_exc() response = create_error_response(SystemExit=True) except UserError as e: sys.stderr.write(str(e) + "\n") response = create_error_response() except KeyboardInterrupt: response = create_error_response( user_exception=self._prepare_user_exception()) except Exception: _report_internal_error() response = create_error_response( context_info="other unhandled exception") if response is False: # Command doesn't want to send any response return elif isinstance(response, dict): if isinstance(cmd, ToplevelCommand): response = ToplevelResponse(command_name=cmd.name, **response) elif isinstance(cmd, InlineCommand): response = InlineResponse(cmd.name, **response) debug("cmd: " + str(cmd) + ", respin: " + str(response)) self.send_message(response)
def _cmd_write_file(self, cmd): def callback(completed, total): self._report_progress(cmd, cmd["path"], completed, total) try: with io.BytesIO() as fp: fp.write(cmd["content_bytes"]) fp.seek(0) self._write_file(fp, cmd["path"], len(cmd["content_bytes"]), callback) error = None except Exception as e: self._report_internal_exception() error = str(e) return InlineResponse( command_name="write_file", path=cmd["path"], editor_id=cmd.get("editor_id"), error=error )
def _cmd_get_editor_calltip(self, cmd): from thonny import jedi_utils signatures = jedi_utils.get_script_signatures( cmd.source, cmd.row, cmd.column, cmd.filename, sys_path=self._get_sys_path_for_analysis(), ) return InlineResponse( "get_editor_calltip", source=cmd.source, row=cmd.row, column=cmd.column, filename=cmd.filename, signatures=signatures, )
def _prepare_command_response( self, response: Union[MessageFromBackend, Dict, None], command: CommandToBackend) -> MessageFromBackend: if "id" in command and "command_id" not in response: response["command_id"] = command["id"] if isinstance(response, MessageFromBackend): return response else: if isinstance(response, dict): args = response else: args = {} if isinstance(command, ToplevelCommand): return ToplevelResponse(command_name=command.name, **args) else: assert isinstance(command, InlineCommand) return InlineResponse(command_name=command.name, **args)
def handle_command(self, cmd): self._report_time("before " + cmd.name) assert isinstance(cmd, (ToplevelCommand, InlineCommand)) if "local_cwd" in cmd: self._local_cwd = cmd["local_cwd"] def create_error_response(**kw): if "error" not in kw: kw["error"] = traceback.format_exc() if isinstance(cmd, ToplevelCommand): return ToplevelResponse(command_name=cmd.name, **kw) else: return InlineResponse(command_name=cmd.name, **kw) handler = getattr(self, "_cmd_" + cmd.name, None) if handler is None: response = create_error_response(error="Unknown command: " + cmd.name) else: try: response = handler(cmd) except SystemExit: # Must be caused by Thonny or plugins code if isinstance(cmd, ToplevelCommand): traceback.print_exc() response = create_error_response(SystemExit=True) except UserError as e: sys.stderr.write(str(e) + "\n") response = create_error_response() except KeyboardInterrupt: response = create_error_response(error="Interrupted", interrupted=True) except ProtocolError as e: self._send_output( "THONNY FAILED TO EXECUTE %s (%s)\n" % (cmd.name, e.message), "stderr") self._send_output("CAPTURED DATA: %r\n" % e.captured, "stderr") self._send_output("TRYING TO RECOVER ...\n", "stderr") # TODO: detect when there is no output for long time and suggest interrupt self._forward_output_until_active_prompt("stdout") response = create_error_response(error=e.message) except Exception: _report_internal_error() response = create_error_response( context_info="other unhandled exception") if response is None: response = {} if response is False: # Command doesn't want to send any response return elif isinstance(response, dict): if isinstance(cmd, ToplevelCommand): response = ToplevelResponse(command_name=cmd.name, **response) elif isinstance(cmd, InlineCommand): response = InlineResponse(cmd.name, **response) if "id" in cmd and "command_id" not in response: response["command_id"] = cmd["id"] debug("cmd: " + str(cmd) + ", respin: " + str(response)) self.send_message(response) self._report_time("after " + cmd.name)
def _handle_normal_command(self, cmd: CommandToBackend) -> None: self._report_time("before " + cmd.name) assert isinstance(cmd, (ToplevelCommand, InlineCommand)) if "local_cwd" in cmd: self._local_cwd = cmd["local_cwd"] def create_error_response(**kw): if "error" not in kw: kw["error"] = traceback.format_exc() if isinstance(cmd, ToplevelCommand): return ToplevelResponse(command_name=cmd.name, **kw) else: return InlineResponse(command_name=cmd.name, **kw) handler = getattr(self, "_cmd_" + cmd.name, None) if handler is None: response = create_error_response(error="Unknown command: " + cmd.name) else: try: response = handler(cmd) except SystemExit: # Must be caused by Thonny or plugins code if isinstance(cmd, ToplevelCommand): traceback.print_exc() response = create_error_response(SystemExit=True) except UserError as e: sys.stderr.write(str(e) + "\n") response = create_error_response() except KeyboardInterrupt: response = create_error_response(error="Interrupted", interrupted=True) except ConnectionClosedException as e: self._on_connection_closed(e) except ManagementError as e: if "KeyboardInterrupt" in e.err: response = create_error_response(error="Interrupted", interrupted=True) else: self._send_output( "THONNY FAILED TO EXECUTE COMMAND %s\n" % cmd.name, "stderr") # traceback.print_exc() # I'll know the trace from command self._show_error("\n") self._show_error("SCRIPT:\n" + e.script + "\n") self._show_error("STDOUT:\n" + e.out + "\n") self._show_error("STDERR:\n" + e.err + "\n") response = create_error_response(error="ManagementError") except Exception: _report_internal_error() response = create_error_response( context_info="other unhandled exception") if response is None: response = {} if response is False: # Command doesn't want to send any response return elif isinstance(response, dict): if isinstance(cmd, ToplevelCommand): response = ToplevelResponse(command_name=cmd.name, **response) elif isinstance(cmd, InlineCommand): response = InlineResponse(cmd.name, **response) debug("cmd: " + str(cmd) + ", respin: " + str(response)) self.send_message(self._prepare_command_response(response, cmd)) self._check_perform_just_in_case_gc() self._report_time("after " + cmd.name)
def create_error_response(**kw): if isinstance(cmd, ToplevelCommand): return ToplevelResponse(command_name=cmd.name, **kw) else: return InlineResponse(command_name=cmd.name, **kw)
def _cmd_get_heap(self, cmd): result = {} for key in self._heap: result[key] = self.export_value(self._heap[key]) return InlineResponse("get_heap", heap=result)
def _cmd_get_object_info(self, cmd): if isinstance(self._current_executor, NiceTracer) and self._current_executor.is_in_past(): info = {"id": cmd.object_id, "error": "past info not available"} elif cmd.object_id in self._heap: value = self._heap[cmd.object_id] attributes = {} if cmd.include_attributes: for name in dir(value): if not name.startswith("__") or cmd.all_attributes: # attributes[name] = inspect.getattr_static(value, name) try: attributes[name] = getattr(value, name) except Exception: pass self._heap[id(type(value))] = type(value) info = { "id": cmd.object_id, "repr": repr(value), "type": str(type(value)), "full_type_name": str(type(value)).replace("<class '", "").replace("'>", "").strip(), "type_id": id(type(value)), "attributes": self.export_variables(attributes), } if isinstance(value, io.TextIOWrapper): self._add_file_handler_info(value, info) elif isinstance( value, ( types.BuiltinFunctionType, types.BuiltinMethodType, types.FunctionType, types.LambdaType, types.MethodType, ), ): self._add_function_info(value, info) elif isinstance(value, (list, tuple, set)): self._add_elements_info(value, info) elif isinstance(value, dict): self._add_entries_info(value, info) elif hasattr(value, "image_data"): info["image_data"] = value.image_data for tweaker in self._object_info_tweakers: try: tweaker(value, info, cmd) except Exception: logger.exception("Failed object info tweaker: " + str(tweaker)) else: info = {"id": cmd.object_id, "error": "object info not available"} return InlineResponse("get_object_info", id=cmd.object_id, info=info)