def __init__(self, error_info): super().__init__(error_info) if "Address already in use" in self.error_info["message"]: self.intro_text = "Your programs tries to listen on a port which is already taken." self.suggestions = [ Suggestion( "kill-by-port-type-error", "Want to close the other process?", self.get_kill_process_instructions(), 5, ), Suggestion( "use-another-type-error", "Can you use another port?", "If you don't want to mess with the other process, then check whether" + " you can configure your program to use another port.", 3, ), ] else: self.intro_text = "No specific information is available for this error."
def _sug_bad_type(self): if self._is_call_function(): action = "call this function on" else: action = "ask this attribute from" return Suggestion( "wrong-type-attribute", "Did you expect another type?", "If you didn't mean %s %s, " % (action, _get_phrase_for_object(self.type_name)) + "then step through your program to see " + "why this type appears here.", 3, )
def _sug_missing_quotes(self): if self._is_attribute_value() or self._is_call_function( ) or self._is_subscript_value(): relevance = 0 else: relevance = 5 return Suggestion( "missing-quotes", "Did you actually mean string (text)?", 'If you didn\'t mean a variable but literal text "%s", then surround it with quotes.' % self.name, relevance, )
def __init__(self, error_info): super().__init__(error_info) self.intro_text = ( "Python was asked to do an operation with an object which " + "doesn't support it.") self.suggestions = [ Suggestion( "step-to-find-type-error", "Did you expect another type?", "Step through your program to see why this type appears here.", 3, ), Suggestion( "look-documentation-type-error", "Maybe you forgot some details about this operation?", "Look up the documentation or perform a web search with the error message.", 2, ), ] # overwrite / add for special cases # something + str or str + something for r, string_first in [ (r"unsupported operand type\(s\) for \+: '(.+?)' and 'str'", False), (r"^Can't convert '(.+?)' object to str implicitly$", True), # Python 3.5 (r"^must be str, not (.+)$", True), # Python 3.6 (r'^can only concatenate str (not "(.+?)") to str$', True), # Python 3.7 ]: m = re.match(r, error_info["message"], re.I) # @UndefinedVariable if m is not None: self._bad_string_concatenation(m.group(1), string_first) return
def _sug_local_from_global(self): relevance = 0 body = None if ( self.last_frame.code_name == "<module>" and self.last_frame_module_ast is not None ): function_names = set() for node in ast.walk(self.last_frame_module_ast): if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): if self.name in map(lambda x: x.arg, node.args.args): function_names.add(node.name) # TODO: varargs, kw, ... declared_global = False for localnode in ast.walk(node): # print(node.name, localnode) if ( isinstance(localnode, ast.Name) and localnode.id == self.name and isinstance(localnode.ctx, ast.Store) ): function_names.add(node.name) elif ( isinstance(localnode, ast.Global) and self.name in localnode.names ): declared_global = True if node.name in function_names and declared_global: function_names.remove(node.name) if function_names: relevance = 9 body = ( ( "Name `%s` defined in `%s` is not accessible in the global/module level." % (self.name, " and ".join(function_names)) ) + "\n\nIf you need that data at the global level, then consider changing the function so that it `return`-s the value." ) return Suggestion( "local-from-global", "Are you trying to acces a local variable outside of the function?", body, relevance, )
def _sug_bad_spelling(self): # Yes, it would be more proper to consult builtins from the backend, # but it's easier this way... all_names = { name for name in dir(builtins) if not name.startswith("_") } all_names |= {"pass", "break", "continue", "return", "yield"} if self.last_frame.globals is not None: all_names |= set(self.last_frame.globals.keys()) if self.last_frame.locals is not None: all_names |= set(self.last_frame.locals.keys()) similar_names = {self.name} if all_names: relevance = 0 for name in all_names: sim = name_similarity(name, self.name) if sim > 4: similar_names.add(name) relevance = max(sim, relevance) else: relevance = 3 if len(similar_names) > 1: body = "I found similar names. Are all of them spelled correctly?\n\n" for name in sorted(similar_names, key=lambda x: x.lower()): # TODO: add location info body += "* `%s`\n\n" % name else: body = ( "Compare the name with corresponding definition / assignment / documentation." + " Don't forget that case of the letters matters!") return Suggestion("bad-spelling-name", "Did you misspell it (somewhere)?", body, relevance)
def _sug_wrong_attribute_instead_of_len(self): if self.type_name == "str": goal = "length" elif self.type_name == "bytes": goal = "number of bytes" elif self.type_name == "list": goal = "number of elements" elif self.type_name == "tuple": goal = "number of elements" elif self.type_name == "set": goal = "number of elements" elif self.type_name == "dict": goal = "number of entries" else: return None return Suggestion( "wrong-attribute-instead-of-len", "Did you mean to ask the %s?" % goal, "This can be done with function `len`, eg:\n\n`len(%s)`" % _get_sample_for_type(self.type_name), (9 if self.att_name.lower() in ("len", "length", "size") else 0), )
def _sug_missing_or_misplaced_colon(self): import tokenize i = 0 title = "Did you forget the colon?" relevance = 0 body = "" while i < len(self.tokens) and self.tokens[i].type != token.ENDMARKER: t = self.tokens[i] if t.string in [ "if", "elif", "else", "while", "for", "with", "try", "except", "finally", "class", "def", ]: keyword_pos = i while ( self.tokens[i].type not in [ token.NEWLINE, token.ENDMARKER, token.COLON, # colon may be OP token.RBRACE, ] and self.tokens[i].string != ":" ): old_i = i if self.tokens[i].string in "([{": i = self._skip_braced_part(i) assert i > old_i if i == len(self.tokens): return None else: i += 1 if self.tokens[i].string != ":": relevance = 9 body = "`%s` header must end with a colon." % t.string break # Colon was present, but maybe it should have been right # after the keyword. if ( t.string in ["else", "try", "finally"] and self.tokens[keyword_pos + 1].string != ":" ): title = "Incorrect use of `%s`" % t.string body = "Nothing is allowed between `%s` and colon." % t.string relevance = 9 if ( self.tokens[keyword_pos + 1].type not in (token.NEWLINE, tokenize.COMMENT) and t.string == "else" ): body = "If you want to specify a conditon, then use `elif` or nested `if`." break i += 1 return Suggestion("missing-or-misplaced-colon", title, body, relevance)
def _sug_missing_import(self): likely_importable_functions = { "math": {"ceil", "floor", "sqrt", "sin", "cos", "degrees"}, "random": {"randint"}, "turtle": { "left", "right", "forward", "fd", "goto", "setpos", "Turtle", "penup", "up", "pendown", "down", "color", "pencolor", "fillcolor", "begin_fill", "end_fill", "pensize", "width", }, "re": {"search", "match", "findall"}, "datetime": {"date", "time", "datetime", "today"}, "statistics": { "mean", "median", "median_low", "median_high", "mode", "pstdev", "pvariance", "stdev", "variance", }, "os": {"listdir"}, "time": {"time", "sleep"}, } body = None if self._is_call_function(): relevance = 5 for mod in likely_importable_functions: if self.name in likely_importable_functions[mod]: relevance += 3 body = ( "If you meant `%s` from module `%s`, then add\n\n`from %s import %s`\n\nto the beginning of your script." % (self.name, mod, mod, self.name) ) break elif self._is_attribute_value(): relevance = 5 body = ( "If you meant module `%s`, then add `import %s` to the beginning of your script" % (self.name, self.name) ) if self.name in likely_importable_functions: relevance += 3 elif self._is_subscript_value() and self.name != "argv": relevance = 0 elif self.name == "pi": body = "If you meant the constant π, then add `from math import pi` to the beginning of your script." relevance = 8 elif self.name == "argv": body = "If you meant the list with program arguments, then add `from sys import argv` to the beginning of your script." relevance = 8 else: relevance = 3 if body is None: body = "Some functions/variables need to be imported before they can be used." return Suggestion("missing-import", "Did you forget to import it?", body, relevance)
def _sug_unbalanced_parens(self): problem = self._find_first_braces_problem() if not problem: return None return Suggestion("missing-or-misplaced-colon", "Unbalanced brackets", problem[1], 8)