def main(raw_args: Sequence[str]) -> int: parser = argparse.ArgumentParser( description= ("Inserts `# lint-fixme` comments into a file where lint violations are " + "found.\n" + "\n" + "You should only use this tool if it's not feasible to fix the existing " + "violations."), parents=[ get_rule_parser(), get_paths_parser(), get_skip_autoformatter_parser(), get_compact_parser(), get_metadata_cache_parser(), get_multiprocessing_parser(), ], ) parser.add_argument( "--kind", default="fixme", choices=[kind.name.lower() for kind in SuppressionCommentKind], help= "Should we use `# lint-fixme` or `# lint-ignore`? Defaults to 'fixme'.", ) message_group = parser.add_mutually_exclusive_group() message_group.add_argument( "--message", default=None, help="Overrides the lint message used in the fixme comment.", ) message_group.add_argument( "--no-message", action="store_true", help= ("Don't include a message with the suppression comment. Only include the " + "lint code."), ) parser.add_argument( "--max-lines", default=3, type=int, help= "The maximum number of lines a comment can span before getting truncated", ) args = parser.parse_args(raw_args) width = shutil.get_terminal_size(fallback=(80, 24)).columns # Find files if directory was provided. file_paths = tuple(find_files((str(p) for p in args.paths))) if not args.compact: print(f"Scanning {len(file_paths)} files") print() start_time = time.time() if args.no_message: message = MessageKind.NO_MESSAGE elif args.message is not None: message = args.message else: message = MessageKind.USE_LINT_REPORT metadata_caches: Optional[Mapping[str, Mapping["ProviderT", object]]] = None if rules_require_metadata_cache({args.rule}): metadata_caches = get_metadata_caches(args.cache_timeout, file_paths) # opts is a more type-safe version of args that we pass around opts = InsertSuppressionsOpts( rule=args.rule, skip_autoformatter=args.skip_autoformatter, kind=SuppressionCommentKind[args.kind.upper()], message=message, max_lines=args.max_lines, formatter=SuppressedLintRuleReportFormatter(width, args.compact), ) formatted_reports_iter = itertools.chain.from_iterable( map_paths( get_formatted_reports_for_path, file_paths, opts, workers=args.workers, metadata_caches=metadata_caches, )) formatted_reports = [] for formatted_report in formatted_reports_iter: # Reports are yielded as soon as they're available. Stream the output to the # terminal. print(formatted_report) # save the report from the iterator for later use formatted_reports.append(formatted_report) if not args.compact: print() print( f"Found {len(formatted_reports)} reports in {len(file_paths)} files in " + f"{time.time() - start_time :.2f} seconds.") return 0
def test_rule_parser_external_module(self) -> None: # External modules work, as long as they are a dependency parser = get_rule_parser().parse_args( ["libcst.codemod.commands.noop.NOOPCommand"]) self.assertEqual(parser.rule, NOOPCommand)
def get_fixture_path(fixture_top_dir: Path, rule_module: str, rules_package: str) -> Path: subpackage: str = rule_module.split(f"{rules_package}.", 1)[-1] fixture_subdir = subpackage.replace(".", "/") return fixture_top_dir / fixture_subdir if __name__ == "__main__": """ Run this script directly to generate pyre data for a lint rule that requires TypeInferenceProvider metadata. """ parser = argparse.ArgumentParser( description= "Generate fixture files required to run unit tests on `TypeInference`-dependent lint rules.", parents=[ get_rule_parser(), get_pyre_fixture_dir_parser(), get_rules_package_parser(), ], ) args: argparse.Namespace = parser.parse_args() rule: LintRuleT = args.rule fixture_dir: Path = args.fixture_dir fixture_path: Path = get_fixture_path(fixture_dir, rule.__module__, args.rules_package) if not issubclass(rule, CstLintRule): raise RuleTypeError("Rule must inherit from CstLintRule.") gen_types(cast(CstLintRule, rule), fixture_path)
def test_rule_parser(self) -> None: parser = get_rule_parser().parse_args( ["fixit.cli.tests.test_args.SomeFakeRule"]) self.assertEqual(parser.rule, SomeFakeRule)