def _get_imported_user_files(main_file, source=None): assert os.path.isabs(main_file) if source is None: source = read_source(main_file) try: root = ast.parse(source, main_file) except SyntaxError: return set() main_dir = os.path.dirname(main_file) module_names = set() # TODO: at the moment only considers non-package modules for node in ast.walk(root): if isinstance(node, ast.Import): for item in node.names: module_names.add(item.name) elif isinstance(node, ast.ImportFrom): module_names.add(node.module) imported_files = set() for file in { name + ext for ext in [".py", ".pyw"] for name in module_names }: possible_path = os.path.join(main_dir, file) if os.path.exists(possible_path): imported_files.add(possible_path) return imported_files
def __init__(self, error_info): # TODO: don't repeat all this for all error helpers self.error_info = error_info self.last_frame = error_info["stack"][-1] self.last_frame_ast = None if self.last_frame.source: try: self.last_frame_ast = ast.parse(self.last_frame.source, self.last_frame.filename) except SyntaxError: pass self.last_frame_module_source = None self.last_frame_module_ast = None if self.last_frame.code_name == "<module>": self.last_frame_module_source = self.last_frame.source self.last_frame_module_ast = self.last_frame_ast elif self.last_frame.filename is not None: try: self.last_frame_module_source = read_source( self.last_frame.filename) self.last_frame_module_ast = ast.parse( self.last_frame_module_source) except Exception: pass self.intro_confidence = 1 self.intro_text = "" self.suggestions = []
def handle_toplevel_response(self, msg: ToplevelResponse) -> None: # Can be called by event system or by Workbench # (if Assistant wasn't created yet but an error came) if not msg.get("user_exception") and msg.get("command_name") in [ "execute_system_command", "execute_source", ]: # Shell commands may be used to investigate the problem, don't clear assistance return self._clear() from thonny.plugins.cpython import CPythonProxy if not isinstance(get_runner().get_backend_proxy(), CPythonProxy): # TODO: add some support for MicroPython as well return # prepare for snapshot key = msg.get("filename", "<pyshell>") self._current_snapshot = { "timestamp": datetime.datetime.now().isoformat()[:19], "main_file_path": key, } self._snapshots_per_main_file.setdefault(key, []) self._snapshots_per_main_file[key].append(self._current_snapshot) if msg.get("user_exception"): if not msg["user_exception"].get("message", None): msg["user_exception"]["message"] = "<no message>" self._exception_info = msg["user_exception"] self._explain_exception(msg["user_exception"]) if get_workbench().get_option( "assistance.open_assistant_on_errors"): get_workbench().show_view("AssistantView", set_focus=False) else: self._exception_info = None if msg.get("filename") and os.path.exists(msg["filename"]): self.main_file_path = msg["filename"] source = read_source(msg["filename"]) self._start_program_analyses( msg["filename"], source, _get_imported_user_files(msg["filename"], source)) else: self.main_file_path = None self._present_conclusion()
def _start_program_analyses(self, main_file_path, main_file_source, imported_file_paths): for cls in _program_analyzer_classes: analyzer = cls(self._accept_warnings) if analyzer.is_enabled(): self._analyzer_instances.append(analyzer) if not self._analyzer_instances: return self._append_text("\nAnalyzing your code ...", ("em",)) # save snapshot of current source self._current_snapshot["main_file_path"] = main_file_path self._current_snapshot["main_file_source"] = main_file_source self._current_snapshot["imported_files"] = { name: read_source(name) for name in imported_file_paths } # start the analysis for analyzer in self._analyzer_instances: analyzer.start_analysis(main_file_path, imported_file_paths)