def test_type_inference_with_timeout(self, gen_cache: MagicMock) -> None:
        timeout = 1
        timeout_error = subprocess.TimeoutExpired(cmd="pyre query ...",
                                                  timeout=timeout)
        gen_cache.side_effect = timeout_error

        paths = (str(self.DUMMY_PATH), )
        type_caches = get_repo_caches(
            paths, FullRepoMetadataConfig({TypeInferenceProvider}, timeout))

        reports = next(
            map_paths(
                operation=self.mock_operation,
                paths=paths,
                config={DummyTypeDependentRule},
                workers=LintWorkers.USE_CURRENT_THREAD,
                metadata_caches=type_caches,
            ))

        # Expecting a placeholder cache to have been plugged in instead.
        self.mock_operation.assert_called_with(
            self.DUMMY_PATH,
            {DummyTypeDependentRule},
            {TypeInferenceProvider: {
                "types": []
            }},
        )

        self.assertEqual(len(reports), 1)
Example #2
0
def call_map_paths_and_print_reports(
    file_paths: Iterable[str],
    opts: LintOpts,
    workers: LintWorkers,
    metadata_caches: Optional[Mapping[str, Mapping["ProviderT",
                                                   object]]] = None,
) -> int:
    """
    Calls map_paths with `apply_fix_operation`, and the passed in file_paths, opts, workers, metadata_cache.
    Returns the number of reports in the files.
    """
    num_reports = 0
    formatted_reports_iter = itertools.chain.from_iterable(
        map_paths(
            apply_fix_operation,
            file_paths,
            opts,
            workers=workers,
            metadata_caches=metadata_caches,
        ))

    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)
        num_reports += 1
    return num_reports
def _main(args: argparse.Namespace) -> int:
    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
Example #4
0
def _main(args: argparse.Namespace) -> int:
    width = shutil.get_terminal_size(fallback=(80, 24)).columns

    # expand path if it's a directory
    file_paths = tuple(find_files(args.paths))
    all_rules = args.rules

    if not args.compact:
        print(f"Scanning {len(file_paths)} files")
        print(f"Testing {len(all_rules)} rules")
        print()
    start_time = time.time()

    metadata_caches: Optional[Mapping[str, Mapping["ProviderT", object]]] = None
    if rules_require_metadata_cache(all_rules):
        metadata_caches = get_metadata_caches(args.cache_timeout, file_paths)

    # opts is a more type-safe version of args that we pass around
    opts = LintOpts(
        rules=all_rules,
        use_ignore_byte_markers=args.use_ignore_byte_markers,
        use_ignore_comments=args.use_ignore_comments,
        formatter=LintRuleReportFormatter(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 with an exit code of 1 if there are any violations found.
    return int(bool(formatted_reports))
Example #5
0
    def test_extra_opts(self) -> None:
        path = "path.py"
        results = next(
            map_paths(
                mock_operation,
                [path],
                self.opts,
                workers=LintWorkers.USE_CURRENT_THREAD,
            ))

        # Assert global list has been modified as expected.
        self.assertEqual(list(self.global_list), [path])

        # Assert the rest of the reporting functionality is as expected
        self.assertEqual(len(results), 1)
        self.assertEqual(results[0].reports, ["fake picklable report"])
    def test_basic_type_inference_multiple_paths(self,
                                                 gen_cache: MagicMock) -> None:
        paths = (str(self.DUMMY_PATH), str(self.DUMMY_PATH_2))
        gen_cache.return_value = {path: self.fake_pyre_data for path in paths}

        type_caches: Mapping[str, Dict[ProviderT, object]] = get_repo_caches(
            paths, FullRepoMetadataConfig({TypeInferenceProvider}, 1))

        all_reports = map_paths(
            operation=self.mock_operation,
            paths=paths,
            config={DummyTypeDependentRule},
            workers=LintWorkers.USE_CURRENT_THREAD,
            metadata_caches=type_caches,
        )

        # Reports should be returned in order since we specified `LintWorkers.USE_CURRENT_THREAD`.
        for i, reports in enumerate(all_reports):
            self.assertEqual(len(reports), 1)
            self.assertEqual(reports[0].file_path, Path(paths[i]))
Example #7
0
    def test_extra_opts_multiple_paths(self) -> None:
        paths = ["path1.py", "path2.py"]
        results_iter = map_paths(mock_operation,
                                 paths,
                                 self.opts,
                                 workers=LintWorkers.USE_CURRENT_THREAD)
        results_count = 0
        paths_reported = []
        for results in results_iter:
            for result in results:
                results_count += 1
                paths_reported.append(result.path)
                self.assertEqual(len(result.reports), 1)
                self.assertEqual(result.reports, ["fake picklable report"])

        # Assert global list has been modified as expected.
        self.assertCountEqual(list(self.global_list), paths)

        # Assert all passed in paths have been visited as expected
        self.assertCountEqual(paths_reported, paths)
    def test_basic_type_inference(self, gen_cache: MagicMock) -> None:
        # We want to intercept any calls that will require the pyre engine to be running.
        gen_cache.return_value = {str(self.DUMMY_PATH): self.fake_pyre_data}
        paths = (str(path) for path in [self.DUMMY_PATH])
        type_caches: Mapping[str, Dict[ProviderT, object]] = get_repo_caches(
            paths, FullRepoMetadataConfig({TypeInferenceProvider}, 1))
        paths = (path for path in type_caches.keys())

        reports = next(
            map_paths(
                operation=self.mock_operation,
                paths=(path for path in type_caches.keys()),
                config={DummyTypeDependentRule},
                workers=LintWorkers.USE_CURRENT_THREAD,
                metadata_caches=type_caches,
            ))

        self.mock_operation.assert_called_with(
            self.DUMMY_PATH, {DummyTypeDependentRule},
            type_caches[str(self.DUMMY_PATH)])

        self.assertEqual(len(reports), 1)
        self.assertEqual(reports[0].file_path, self.DUMMY_PATH)
Example #9
0
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
Example #10
0
def main(raw_args: Sequence[str]) -> int:
    parser = argparse.ArgumentParser(
        description=(
            "Validates your lint rules by running them against the specified, "
            + "directory or file(s). This is not a substitute for unit tests, "
            + "but it can provide additional confidence in your lint rules.\n"
            + "If no lint rules or packages are specified, runs all lint rules "
            + "found in the packages specified in `fixit.config.yaml`."
        ),
        parents=[
            get_paths_parser(),
            get_rules_parser(),
            get_use_ignore_comments_parser(),
            get_skip_ignore_byte_marker_parser(),
            get_compact_parser(),
            get_multiprocessing_parser(),
        ],
    )

    parser.add_argument(
        "--cache-timeout",
        type=int,
        help="Timeout (seconds) for metadata cache fetching. Default is 2 seconds.",
        default=2,
    )

    args = parser.parse_args(raw_args)
    width = shutil.get_terminal_size(fallback=(80, 24)).columns

    # expand path if it's a directory
    file_paths = tuple(find_files(args.paths))
    all_rules = args.rules

    if not args.compact:
        print(f"Scanning {len(file_paths)} files")
        print(f"Testing {len(all_rules)} rules")
        print()
    start_time = time.time()

    metadata_caches: Optional[Mapping[str, Mapping["ProviderT", object]]] = None
    if rules_require_metadata_cache(all_rules):
        metadata_caches = get_metadata_caches(args.cache_timeout, file_paths)

    # opts is a more type-safe version of args that we pass around
    opts = LintOpts(
        rules=all_rules,
        use_ignore_byte_markers=args.use_ignore_byte_markers,
        use_ignore_comments=args.use_ignore_comments,
        formatter=LintRuleReportFormatter(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 with an exit code of 1 if there are any violations found.
    return int(bool(formatted_reports))