Beispiel #1
0
async def docformatter_lint(configs: DocformatterConfigurations,
                            docformatter: Docformatter) -> LintResult:
    if docformatter.options.skip:
        return LintResult.noop()
    setup = await Get[Setup](SetupRequest(configs, check_only=True))
    result = await Get[FallibleProcessResult](Process, setup.process)
    return LintResult.from_fallible_process_result(result)
Beispiel #2
0
async def black_lint(field_sets: BlackFieldSets, black: Black) -> LintResult:
    if black.options.skip:
        return LintResult.noop()
    setup = await Get[Setup](SetupRequest(field_sets, check_only=True))
    result = await Get[FallibleProcessResult](Process, setup.process)
    return LintResult.from_fallible_process_result(result,
                                                   linter_name="Black",
                                                   strip_chroot_path=True)
Beispiel #3
0
 def test_precise_file_args(self) -> None:
     target = self.make_target_with_origin(
         [self.good_source, self.bad_source],
         origin=FilesystemLiteralSpec(self.good_source.path))
     lint_result, fmt_result = self.run_docformatter([target])
     assert lint_result == LintResult.noop()
     assert fmt_result.digest == self.get_digest(
         [self.good_source, self.bad_source])
Beispiel #4
0
async def isort_lint(field_sets: IsortFieldSets, isort: Isort) -> LintResult:
    if isort.options.skip:
        return LintResult.noop()
    setup = await Get[Setup](SetupRequest(field_sets, check_only=True))
    result = await Get[FallibleProcessResult](Process, setup.process)
    return LintResult.from_fallible_process_result(result,
                                                   linter_name="isort",
                                                   strip_chroot_path=True)
Beispiel #5
0
async def docformatter_lint(field_sets: DocformatterFieldSets,
                            docformatter: Docformatter) -> LintResult:
    if docformatter.options.skip:
        return LintResult.noop()
    setup = await Get[Setup](SetupRequest(field_sets, check_only=True))
    result = await Get[FallibleProcessResult](Process, setup.process)
    return LintResult.from_fallible_process_result(result,
                                                   linter_name="Docformatter")
Beispiel #6
0
async def bandit_lint(
    configs: BanditConfigurations,
    bandit: Bandit,
    python_setup: PythonSetup,
    subprocess_encoding_environment: SubprocessEncodingEnvironment,
) -> LintResult:
    if bandit.options.skip:
        return LintResult.noop()

    # NB: Bandit output depends upon which Python interpreter version it's run with. See
    # https://github.com/PyCQA/bandit#under-which-version-of-python-should-i-install-bandit.
    interpreter_constraints = PexInterpreterConstraints.create_from_compatibility_fields(
        (config.compatibility for config in configs), python_setup=python_setup
    )
    requirements_pex = await Get[Pex](
        PexRequest(
            output_filename="bandit.pex",
            requirements=PexRequirements(bandit.get_requirement_specs()),
            interpreter_constraints=interpreter_constraints,
            entry_point=bandit.get_entry_point(),
        )
    )

    config_path: Optional[str] = bandit.options.config
    config_snapshot = await Get[Snapshot](
        PathGlobs(
            globs=tuple([config_path] if config_path else []),
            glob_match_error_behavior=GlobMatchErrorBehavior.error,
            description_of_origin="the option `--bandit-config`",
        )
    )

    all_source_files = await Get[SourceFiles](
        AllSourceFilesRequest(config.sources for config in configs)
    )
    specified_source_files = await Get[SourceFiles](
        SpecifiedSourceFilesRequest((config.sources, config.origin) for config in configs)
    )

    merged_input_files = await Get[Digest](
        MergeDigests(
            (all_source_files.snapshot.digest, requirements_pex.digest, config_snapshot.digest)
        ),
    )

    address_references = ", ".join(sorted(config.address.reference() for config in configs))

    process = requirements_pex.create_process(
        python_setup=python_setup,
        subprocess_encoding_environment=subprocess_encoding_environment,
        pex_path=f"./bandit.pex",
        pex_args=generate_args(specified_source_files=specified_source_files, bandit=bandit),
        input_files=merged_input_files,
        description=f"Run Bandit on {pluralize(len(configs), 'target')}: {address_references}.",
    )
    result = await Get[FallibleProcessResult](Process, process)
    return LintResult.from_fallible_process_result(result)
Beispiel #7
0
async def flake8_lint(
    configs: Flake8Configurations,
    flake8: Flake8,
    python_setup: PythonSetup,
    subprocess_encoding_environment: SubprocessEncodingEnvironment,
) -> LintResult:
    if flake8.options.skip:
        return LintResult.noop()

    # NB: Flake8 output depends upon which Python interpreter version it's run with. We ensure that
    # each target runs with its own interpreter constraints. See
    # http://flake8.pycqa.org/en/latest/user/invocation.html.
    interpreter_constraints = PexInterpreterConstraints.create_from_compatibility_fields(
        (config.compatibility for config in configs), python_setup)
    requirements_pex = await Get[Pex](PexRequest(
        output_filename="flake8.pex",
        requirements=PexRequirements(flake8.get_requirement_specs()),
        interpreter_constraints=interpreter_constraints,
        entry_point=flake8.get_entry_point(),
    ))

    config_path: Optional[str] = flake8.options.config
    config_snapshot = await Get[Snapshot](PathGlobs(
        globs=tuple([config_path] if config_path else []),
        glob_match_error_behavior=GlobMatchErrorBehavior.error,
        description_of_origin="the option `--flake8-config`",
    ))

    all_source_files = await Get[SourceFiles](AllSourceFilesRequest(
        config.sources for config in configs))
    specified_source_files = await Get[SourceFiles](
        SpecifiedSourceFilesRequest(
            (config.sources, config.origin) for config in configs))

    merged_input_files = await Get[Digest](DirectoriesToMerge(directories=(
        all_source_files.snapshot.directory_digest,
        requirements_pex.directory_digest,
        config_snapshot.directory_digest,
    )), )

    address_references = ", ".join(
        sorted(config.address.reference() for config in configs))

    process = requirements_pex.create_process(
        python_setup=python_setup,
        subprocess_encoding_environment=subprocess_encoding_environment,
        pex_path=f"./flake8.pex",
        pex_args=generate_args(specified_source_files=specified_source_files,
                               flake8=flake8),
        input_files=merged_input_files,
        description=
        f"Run Flake8 on {pluralize(len(configs), 'target')}: {address_references}.",
    )
    result = await Get[FallibleProcessResult](Process, process)
    return LintResult.from_fallible_process_result(result)
Beispiel #8
0
 def test_respects_passthrough_args(self) -> None:
     needs_config = FileContent(
         path="needs_config.py",
         content=
         b'"""\nOne line docstring acting like it\'s multiline.\n"""\n',
     )
     target = self.make_target_with_origin([needs_config])
     lint_result, fmt_result = self.run_docformatter(
         [target], passthrough_args="--make-summary-multi-line")
     assert lint_result == LintResult.noop()
     assert fmt_result.digest == self.get_digest([needs_config])
 def test_skip(self) -> None:
     target = self.make_target_with_origin([self.bad_source])
     result = self.run_pylint([target], skip=True)
     assert result == LintResult.noop()
 def test_skip(self) -> None:
     target = self.make_target_with_origin([self.bad_source])
     lint_result, fmt_result = self.run_isort([target], skip=True)
     assert lint_result == LintResult.noop()
     assert fmt_result == FmtResult.noop()
     assert fmt_result.did_change is False
Beispiel #11
0
async def black_lint(configs: BlackConfigurations, black: Black) -> LintResult:
    if black.options.skip:
        return LintResult.noop()
    setup = await Get[Setup](SetupRequest(configs, check_only=True))
    result = await Get[FallibleProcessResult](Process, setup.process)
    return LintResult.from_fallible_process_result(result)
Beispiel #12
0
async def pylint_lint(
    configs: PylintConfigurations,
    pylint: Pylint,
    python_setup: PythonSetup,
    subprocess_encoding_environment: SubprocessEncodingEnvironment,
) -> LintResult:
    if pylint.options.skip:
        return LintResult.noop()

    # Pylint needs direct dependencies in the chroot to ensure that imports are valid. However, it
    # doesn't lint those direct dependencies nor does it care about transitive dependencies.
    addresses = []
    for config in configs:
        addresses.append(config.address)
        addresses.extend(config.dependencies.value or ())
    targets = await Get[Targets](Addresses(addresses))
    chrooted_python_sources = await Get[ImportablePythonSources](Targets,
                                                                 targets)

    # NB: Pylint output depends upon which Python interpreter version it's run with. We ensure that
    # each target runs with its own interpreter constraints. See
    # http://pylint.pycqa.org/en/latest/faq.html#what-versions-of-python-is-pylint-supporting.
    interpreter_constraints = PexInterpreterConstraints.create_from_compatibility_fields(
        (config.compatibility for config in configs), python_setup)
    requirements_pex = await Get[Pex](PexRequest(
        output_filename="pylint.pex",
        requirements=PexRequirements(pylint.get_requirement_specs()),
        interpreter_constraints=interpreter_constraints,
        entry_point=pylint.get_entry_point(),
    ))

    config_path: Optional[str] = pylint.options.config
    config_snapshot = await Get[Snapshot](PathGlobs(
        globs=tuple([config_path] if config_path else []),
        glob_match_error_behavior=GlobMatchErrorBehavior.error,
        description_of_origin="the option `--pylint-config`",
    ))

    merged_input_files = await Get[Digest](DirectoriesToMerge(directories=(
        requirements_pex.directory_digest,
        config_snapshot.directory_digest,
        chrooted_python_sources.snapshot.directory_digest,
    )), )

    specified_source_files = await Get[SourceFiles](
        SpecifiedSourceFilesRequest(
            ((config.sources, config.origin) for config in configs),
            strip_source_roots=True))

    address_references = ", ".join(
        sorted(config.address.reference() for config in configs))

    process = requirements_pex.create_process(
        python_setup=python_setup,
        subprocess_encoding_environment=subprocess_encoding_environment,
        pex_path=f"./pylint.pex",
        pex_args=generate_args(specified_source_files=specified_source_files,
                               pylint=pylint),
        input_files=merged_input_files,
        description=
        f"Run Pylint on {pluralize(len(configs), 'target')}: {address_references}.",
    )
    result = await Get[FallibleProcessResult](Process, process)
    return LintResult.from_fallible_process_result(result)
Beispiel #13
0
 def test_passing_source(self) -> None:
     target = self.make_target_with_origin([self.good_source])
     lint_result, fmt_result = self.run_docformatter([target])
     assert lint_result == LintResult.noop()
     assert fmt_result.digest == self.get_digest([self.good_source])
Beispiel #14
0
 def test_skip(self) -> None:
     target = self.make_target_with_origin([self.bad_source])
     lint_result, fmt_result = self.run_docformatter([target], skip=True)
     assert lint_result == LintResult.noop()
     assert fmt_result == FmtResult.noop()
Beispiel #15
0
async def pylint_lint(
    field_sets: PylintFieldSets,
    pylint: Pylint,
    python_setup: PythonSetup,
    subprocess_encoding_environment: SubprocessEncodingEnvironment,
) -> LintResult:
    if pylint.skip:
        return LintResult.noop()

    # Pylint needs direct dependencies in the chroot to ensure that imports are valid. However, it
    # doesn't lint those direct dependencies nor does it care about transitive dependencies.
    addresses_with_dependencies = []
    for field_set in field_sets:
        addresses_with_dependencies.append(field_set.address)
        addresses_with_dependencies.extend(field_set.dependencies.value or ())
    targets = await Get[Targets](Addresses(addresses_with_dependencies))

    # NB: Pylint output depends upon which Python interpreter version it's run with. We ensure that
    # each target runs with its own interpreter constraints. See
    # http://pylint.pycqa.org/en/latest/faq.html#what-versions-of-python-is-pylint-supporting.
    interpreter_constraints = PexInterpreterConstraints.create_from_compatibility_fields(
        (field_set.compatibility for field_set in field_sets), python_setup)

    # We build one PEX with Pylint requirements and another with all direct 3rd-party dependencies.
    # Splitting this into two PEXes gives us finer-grained caching. We then merge via `--pex-path`.
    pylint_pex_request = Get[Pex](PexRequest(
        output_filename="pylint.pex",
        requirements=PexRequirements(pylint.get_requirement_specs()),
        interpreter_constraints=interpreter_constraints,
        entry_point=pylint.get_entry_point(),
    ))
    requirements_pex_request = Get[Pex](PexRequest(
        output_filename="requirements.pex",
        requirements=PexRequirements.create_from_requirement_fields(
            tgt[PythonRequirementsField] for tgt in targets
            if tgt.has_field(PythonRequirementsField)),
        interpreter_constraints=interpreter_constraints,
    ))
    pylint_runner_pex_request = Get[Pex](
        PexRequest(
            output_filename="pylint_runner.pex",
            entry_point=pylint.get_entry_point(),
            interpreter_constraints=interpreter_constraints,
            additional_args=(
                "--pex-path",
                # TODO(John Sirois): Support shading python binaries:
                #   https://github.com/pantsbuild/pants/issues/9206
                # Right now any Pylint transitive requirements will shadow corresponding user
                # requirements which could lead to problems.
                ":".join(["pylint.pex", "requirements.pex"]),
            ),
        ))

    config_snapshot_request = Get[Snapshot](PathGlobs(
        globs=[pylint.config] if pylint.config else [],
        glob_match_error_behavior=GlobMatchErrorBehavior.error,
        description_of_origin="the option `--pylint-config`",
    ))

    prepare_python_sources_request = Get[ImportablePythonSources](Targets,
                                                                  targets)
    specified_source_files_request = Get[SourceFiles](
        SpecifiedSourceFilesRequest(
            ((field_set.sources, field_set.origin)
             for field_set in field_sets),
            strip_source_roots=True,
        ))

    (
        pylint_pex,
        requirements_pex,
        pylint_runner_pex,
        config_snapshot,
        prepared_python_sources,
        specified_source_files,
    ) = cast(
        Tuple[Pex, Pex, Pex, Snapshot, ImportablePythonSources, SourceFiles],
        await MultiGet([
            pylint_pex_request,
            requirements_pex_request,
            pylint_runner_pex_request,
            config_snapshot_request,
            prepare_python_sources_request,
            specified_source_files_request,
        ]),
    )

    input_digest = await Get[Digest](MergeDigests((
        pylint_pex.digest,
        requirements_pex.digest,
        pylint_runner_pex.digest,
        config_snapshot.digest,
        prepared_python_sources.snapshot.digest,
    )), )

    address_references = ", ".join(
        sorted(field_set.address.reference() for field_set in field_sets))

    process = requirements_pex.create_process(
        python_setup=python_setup,
        subprocess_encoding_environment=subprocess_encoding_environment,
        pex_path=f"./pylint_runner.pex",
        pex_args=generate_args(specified_source_files=specified_source_files,
                               pylint=pylint),
        input_digest=input_digest,
        description=
        f"Run Pylint on {pluralize(len(field_sets), 'target')}: {address_references}.",
    )
    result = await Get[FallibleProcessResult](Process, process)
    return LintResult.from_fallible_process_result(result,
                                                   linter_name="Pylint")