def _format_warning(self, warning, last): title = rst_utils.escape(warning["msg"].splitlines()[0]) if warning.get("lineno") is not None: url = self._format_file_url(warning) if warning.get("lineno"): title = "`Line %d <%s>`__ : %s" % (warning["lineno"], url, title) if warning.get("explanation_rst"): explanation_rst = warning["explanation_rst"] elif warning.get("explanation"): explanation_rst = rst_utils.escape(warning["explanation"]) else: explanation_rst = "" if warning.get("more_info_url"): explanation_rst += "\n\n`More info online <%s>`__" % warning[ "more_info_url"] explanation_rst = explanation_rst.strip() topic_class = "toggle" if explanation_rst else "empty" if not explanation_rst: explanation_rst = "n/a" return (".. topic:: %s\n" % title + " :class: " + topic_class + ("" if last else ", tight") + "\n" + " \n" + textwrap.indent(explanation_rst, " ") + "\n\n")
def __init__(self, error_info): super().__init__(error_info) self.intro_text = "No specific suggestions for this error (yet)." self.intro_confidence = 1 self.suggestions = [ Suggestion( "ask-for-specific-support", "Let Thonny developers know", "Click on the feedback link at the bottom of this panel to let Thonny developers know " + "about your problem. They may add support for " + "such cases in future Thonny versions.", 1, ) ] if error_info["message"].lower() != "invalid syntax": self.suggestions.append( Suggestion( "generic-search-the-web", "Search the web", "Try performing a web search for\n\n``Python %s: %s``" % ( self.error_info["type_name"], rst_utils.escape(self.error_info["message"].replace( "\n", " ").strip()), ), 1, ))
def format_file_url(filename, lineno, col_offset): s = "thonny-editor://" + rst_utils.escape(filename).replace(" ", "%20") if lineno is not None: s += "#" + str(lineno) if col_offset is not None: s += ":" + str(col_offset) return s
def _get_warnings(self, main_file_path): # TODO: current dir may be different main_file_dir = os.path.dirname(main_file_path) if not os.path.isdir(main_file_dir): return [] library_modules = known_stdlib_modules | self._get_3rd_party_modules() for item in os.listdir(main_file_dir): full_path = os.path.join(main_file_dir, item) if item.endswith(".py") and item[:-3] in library_modules: if is_same_path(full_path, main_file_path): prelude = "Your program file is named '%s'." % item rename_hint = " (*Run → Rename…* )" else: prelude = ( "Your working directory `%s <%s>`__ contains a file named '%s'.\n\n" % ( rst_utils.escape(main_file_dir), rst_utils.escape(main_file_dir), item, )) rename_hint = "" yield { "filename": full_path, "lineno": 0, "symbol": "file-shadows-library-module", "msg": "Possibly bad file name", "explanation_rst": prelude + "\n\n" + "When you try to import library module ``%s``, your file will be imported instead.\n\n" % item[:-3] + "Rename your '%s'%s to make the library module visible again." % (item, rename_hint), "group": "warnings", "relevance": 5, }
def _explain_exception(self, error_info): rst = ( self._get_rst_prelude() + rst_utils.create_title(error_info["type_name"] + ": " + rst_utils.escape(error_info["message"])) + "\n") if (error_info.get("lineno") is not None and error_info.get("filename") and os.path.exists(error_info["filename"])): rst += "`%s, line %d <%s>`__\n\n" % ( os.path.basename(error_info["filename"]), error_info["lineno"], self._format_file_url(error_info), ) helpers = [ helper_class(error_info) for helper_class in ( _error_helper_classes.get(error_info["type_name"], []) + _error_helper_classes["*"]) ] best_intro = helpers[0] for helper in helpers: if helper.intro_confidence > best_intro.intro_confidence: best_intro = helper # intro if best_intro.intro_text: rst += (".. note::\n" + " " + best_intro.intro_text.strip().replace("\n", "\n\n ") + "\n\n") suggestions = [ suggestion for helper in helpers for suggestion in helper.suggestions if suggestion is not None ] suggestions = sorted(suggestions, key=lambda s: s.relevance, reverse=True) if suggestions[0].relevance > 1 or best_intro.intro_confidence > 1: relevance_threshold = 2 else: # use relevance 1 only when there is nothing better relevance_threshold = 1 suggestions = [ s for s in suggestions if s.relevance >= relevance_threshold ] for i, suggestion in enumerate(suggestions): rst += self._format_suggestion( suggestion, i == len(suggestions) - 1, # TODO: is it good if first is preopened? # It looks cleaner if it is not. False, # i==0 ) self._current_snapshot["exception_suggestions"] = [ dict(sug._asdict()) for sug in suggestions ] self.text.append_rst(rst) self._append_text("\n") self._current_snapshot["exception_type_name"] = error_info["type_name"] self._current_snapshot["exception_message"] = error_info["message"] self._current_snapshot["exception_file_path"] = error_info["filename"] self._current_snapshot["exception_lineno"] = error_info["lineno"] self._current_snapshot["exception_rst"] = rst # for debugging purposes