def generate_unused_ignore_errors(self, file: str) -> None: ignored_lines = self.ignored_lines[file] if not is_typeshed_file(file) and file not in self.ignored_files: ignored_lines = self.ignored_lines[file] used_ignored_lines = self.used_ignored_lines[file] for line, ignored_codes in ignored_lines.items(): used_ignored_codes = used_ignored_lines[line] unused_ignored_codes = set(ignored_codes) - set( used_ignored_codes) # `ignore` is used if len(ignored_codes) == 0 and len(used_ignored_codes) > 0: continue # All codes appearing in `ignore[...]` are used if len(ignored_codes) > 0 and len(unused_ignored_codes) == 0: continue # Display detail only when `ignore[...]` specifies more than one error code unused_codes_message = "" if len(ignored_codes) > 1 and len(unused_ignored_codes) > 0: unused_codes_message = f"[{', '.join(sorted(unused_ignored_codes))}]" message = f'Unused "type: ignore{unused_codes_message}" comment' # Don't use report since add_error_info will ignore the error! info = ErrorInfo(self.import_context(), file, self.current_module(), None, None, line, -1, 'error', message, None, False, False, False) self._add_error_info(file, info)
def generate_ignore_without_code_errors( self, file: str, is_warning_unused_ignores: bool) -> None: if is_typeshed_file(file) or file in self.ignored_files: return used_ignored_lines = self.used_ignored_lines[file] # If the whole file is ignored, ignore it. if used_ignored_lines: _, used_codes = min(used_ignored_lines.items()) if codes.FILE.code in used_codes: return for line, ignored_codes in self.ignored_lines[file].items(): if ignored_codes: continue # If the ignore is itself unused and that would be warned about, let # that error stand alone if is_warning_unused_ignores and not used_ignored_lines[line]: continue codes_hint = '' ignored_codes = sorted(set(used_ignored_lines[line])) if ignored_codes: codes_hint = f' (consider "type: ignore[{", ".join(ignored_codes)}]" instead)' message = f'"type: ignore" comment without error code{codes_hint}' # Don't use report since add_error_info will ignore the error! info = ErrorInfo(self.import_context(), file, self.current_module(), None, None, line, -1, 'error', message, codes.IGNORE_WITHOUT_CODE, False, False, False) self._add_error_info(file, info)
def generate_unused_ignore_errors(self, file: str) -> None: ignored_lines = self.ignored_lines[file] if not is_typeshed_file(file) and file not in self.ignored_files: for line in set(ignored_lines) - self.used_ignored_lines[file]: # Don't use report since add_error_info will ignore the error! info = ErrorInfo(self.import_context(), file, self.current_module(), None, None, line, -1, 'error', 'unused "type: ignore" comment', None, False, False) self._add_error_info(file, info)
def check_type_arguments(graph: 'Graph', scc: List[str], errors: Errors) -> None: for module in scc: state = graph[module] assert state.tree analyzer = TypeArgumentAnalyzer(errors, state.options, is_typeshed_file(state.path or '')) with state.wrap_context(): with strict_optional_set(state.options.strict_optional): state.tree.accept(analyzer)
def check_type_arguments_in_targets(targets: List[FineGrainedDeferredNode], state: 'State', errors: Errors) -> None: """Check type arguments against type variable bounds and restrictions. This mirrors the logic in check_type_arguments() except that we process only some targets. This is used in fine grained incremental mode. """ analyzer = TypeArgumentAnalyzer(errors, state.options, is_typeshed_file(state.path or '')) with state.wrap_context(): with strict_optional_set(state.options.strict_optional): for target in targets: func: Optional[Union[FuncDef, OverloadedFuncDef]] = None if isinstance(target.node, (FuncDef, OverloadedFuncDef)): func = target.node saved = (state.id, target.active_typeinfo, func) # module, class, function with errors.scope.saved_scope(saved) if errors.scope else nothing(): analyzer.recurse_into_functions = func is not None target.node.accept(analyzer)