Beispiel #1
0
async def setup_black(wrapped_target: FormattablePythonTarget, black: Black) -> BlackSetup:
  config_path: Optional[str] = black.get_options().config
  config_snapshot = await Get(Snapshot, PathGlobs(include=(config_path,)))
  resolved_requirements_pex = await Get(
    Pex, CreatePex(
      output_filename="black.pex",
      requirements=PexRequirements(requirements=tuple(black.get_requirement_specs())),
      interpreter_constraints=PexInterpreterConstraints(
        constraint_set=tuple(black.default_interpreter_constraints)
      ),
      entry_point=black.get_entry_point(),
    )
  )

  sources_digest = wrapped_target.target.sources.snapshot.directory_digest

  merged_input_files = await Get(
    Digest,
    DirectoriesToMerge(
      directories=(
        sources_digest,
        resolved_requirements_pex.directory_digest,
        config_snapshot.directory_digest,
      )
    ),
  )
  return BlackSetup(config_path, resolved_requirements_pex, merged_input_files)
async def create_pex_from_target_closure(request: CreatePexFromTargetClosure,
                                         python_setup: PythonSetup) -> Pex:
    transitive_hydrated_targets = await Get[TransitiveHydratedTargets](
        BuildFileAddresses, request.build_file_addresses)
    all_targets = transitive_hydrated_targets.closure
    all_target_adaptors = [t.adaptor for t in all_targets]

    interpreter_constraints = PexInterpreterConstraints.create_from_adaptors(
        adaptors=tuple(all_target_adaptors), python_setup=python_setup)

    if request.include_source_files:
        chrooted_sources = await Get[ChrootedPythonSources](
            HydratedTargets(all_targets))

    requirements = PexRequirements.create_from_adaptors(
        adaptors=all_target_adaptors,
        additional_requirements=request.additional_requirements)

    create_pex_request = CreatePex(
        output_filename=request.output_filename,
        requirements=requirements,
        interpreter_constraints=interpreter_constraints,
        entry_point=request.entry_point,
        input_files_digest=chrooted_sources.digest
        if request.include_source_files else None,
        additional_args=request.additional_args,
    )

    pex = await Get[Pex](CreatePex, create_pex_request)
    return pex
async def create_pex_from_target_closure(request: CreatePexFromTargetClosure,
                                         python_setup: PythonSetup) -> Pex:
    transitive_hydrated_targets = await Get[TransitiveHydratedTargets](
        Addresses, request.addresses)
    all_targets = transitive_hydrated_targets.closure
    all_target_adaptors = [t.adaptor for t in all_targets]

    interpreter_constraints = PexInterpreterConstraints.create_from_adaptors(
        adaptors=all_target_adaptors, python_setup=python_setup)

    input_digests = []
    if request.additional_input_files:
        input_digests.append(request.additional_input_files)
    if request.include_source_files:
        chrooted_sources = await Get[ChrootedPythonSources](
            HydratedTargets(all_targets))
        input_digests.append(chrooted_sources.snapshot.directory_digest)
    merged_input_digest = await Get[Digest](
        DirectoriesToMerge(directories=tuple(input_digests)))
    requirements = PexRequirements.create_from_adaptors(
        adaptors=all_target_adaptors,
        additional_requirements=request.additional_requirements)

    create_pex_request = CreatePex(
        output_filename=request.output_filename,
        requirements=requirements,
        interpreter_constraints=interpreter_constraints,
        entry_point=request.entry_point,
        input_files_digest=merged_input_digest,
        additional_args=request.additional_args,
    )

    pex = await Get[Pex](CreatePex, create_pex_request)
    return pex
Beispiel #4
0
 def create_pex_and_get_all_data(
     self,
     *,
     requirements=PexRequirements(),
     entry_point=None,
     interpreter_constraints=PexInterpreterConstraints(),
     input_files: Optional[Digest] = None,
     additional_pants_args: Tuple[str, ...] = (),
     additional_pex_args: Tuple[str, ...] = (),
 ) -> Dict:
     request = CreatePex(
         output_filename="test.pex",
         requirements=requirements,
         interpreter_constraints=interpreter_constraints,
         entry_point=entry_point,
         input_files_digest=input_files,
         additional_args=additional_pex_args,
     )
     requirements_pex = self.request_single_product(
         Pex,
         Params(
             request,
             create_options_bootstrapper(
                 args=["--backend-packages2=pants.backend.python", *additional_pants_args]
             ),
         ),
     )
     self.scheduler.materialize_directory(
         DirectoryToMaterialize(requirements_pex.directory_digest),
     )
     with zipfile.ZipFile(os.path.join(self.build_root, "test.pex"), "r") as pex:
         with pex.open("PEX-INFO", "r") as pex_info:
             pex_info_content = pex_info.readline().decode()
             pex_list = pex.namelist()
     return {"pex": requirements_pex, "info": json.loads(pex_info_content), "files": pex_list}
Beispiel #5
0
    def create_pex_and_get_all_data(
            self,
            *,
            requirements=PexRequirements(),
            entry_point=None,
            interpreter_constraints=PexInterpreterConstraints(),
            input_files: Digest = None) -> (Dict, List[str]):
        def hashify_optional_collection(iterable):
            return tuple(sorted(iterable)) if iterable is not None else tuple()

        request = CreatePex(
            output_filename="test.pex",
            requirements=requirements,
            interpreter_constraints=interpreter_constraints,
            entry_point=entry_point,
            input_files_digest=input_files,
        )
        requirements_pex = self.request_single_product(
            Pex,
            Params(request, PythonSetup.global_instance(),
                   SubprocessEnvironment.global_instance(),
                   PythonNativeCode.global_instance()))
        self.scheduler.materialize_directory(
            DirectoryToMaterialize(requirements_pex.directory_digest), )
        with zipfile.ZipFile(os.path.join(self.build_root, "test.pex"),
                             "r") as pex:
            with pex.open("PEX-INFO", "r") as pex_info:
                pex_info_content = pex_info.readline().decode()
                pex_list = pex.namelist()
        return {
            'pex': requirements_pex,
            'info': json.loads(pex_info_content),
            'files': pex_list
        }
Beispiel #6
0
def get_black_input(
    wrapped_target: FormattablePythonTarget,
    black: Black,
) -> BlackInput:
    config_path = black.get_options().config
    config_snapshot = yield Get(Snapshot, PathGlobs(include=(config_path, )))

    resolved_requirements_pex = yield Get(
        Pex,
        CreatePex(
            output_filename="black.pex",
            requirements=PexRequirements(
                requirements=tuple(black.get_requirement_specs())),
            interpreter_constraints=PexInterpreterContraints(
                constraint_set=frozenset(
                    black.default_interpreter_constraints)),
            entry_point=black.get_entry_point(),
        ))
    target = wrapped_target.target
    sources_digest = target.sources.snapshot.directory_digest

    all_input_digests = [
        sources_digest,
        resolved_requirements_pex.directory_digest,
        config_snapshot.directory_digest,
    ]
    merged_input_files = yield Get(
        Digest,
        DirectoriesToMerge(directories=tuple(all_input_digests)),
    )
    yield BlackInput(config_path, resolved_requirements_pex,
                     merged_input_files)
Beispiel #7
0
async def setup(
    request: SetupRequest,
    isort: Isort,
    python_setup: PythonSetup,
    subprocess_encoding_environment: SubprocessEncodingEnvironment,
) -> Setup:
    adaptors_with_origins = request.formatter.adaptors_with_origins

    requirements_pex = await Get[Pex](CreatePex(
        output_filename="isort.pex",
        requirements=PexRequirements(isort.get_requirement_specs()),
        interpreter_constraints=PexInterpreterConstraints(
            isort.default_interpreter_constraints),
        entry_point=isort.get_entry_point(),
    ))

    config_path: Optional[List[str]] = isort.options.config
    config_snapshot = await Get[Snapshot](PathGlobs(
        globs=config_path or (),
        glob_match_error_behavior=GlobMatchErrorBehavior.error,
        conjunction=GlobExpansionConjunction.all_match,
        description_of_origin="the option `--isort-config`",
    ))

    if request.formatter.prior_formatter_result is None:
        all_source_files = await Get[SourceFiles](AllSourceFilesRequest(
            adaptor_with_origin.adaptor
            for adaptor_with_origin in adaptors_with_origins))
        all_source_files_snapshot = all_source_files.snapshot
    else:
        all_source_files_snapshot = request.formatter.prior_formatter_result

    specified_source_files = await Get[SourceFiles](
        SpecifiedSourceFilesRequest(adaptors_with_origins))

    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(adaptor_with_origin.adaptor.address.reference()
               for adaptor_with_origin in adaptors_with_origins))

    process_request = requirements_pex.create_execute_request(
        python_setup=python_setup,
        subprocess_encoding_environment=subprocess_encoding_environment,
        pex_path="./isort.pex",
        pex_args=generate_args(
            specified_source_files=specified_source_files,
            isort=isort,
            check_only=request.check_only,
        ),
        input_files=merged_input_files,
        output_files=all_source_files_snapshot.files,
        description=f"Run isort for {address_references}",
    )
    return Setup(process_request)
def create_python_binary(python_binary_adaptor: PythonBinaryAdaptor,
                         python_setup: PythonSetup) -> CreatedBinary:
    transitive_hydrated_targets = yield Get(
        TransitiveHydratedTargets,
        BuildFileAddresses((python_binary_adaptor.address, )))
    all_targets = transitive_hydrated_targets.closure
    all_target_adaptors = [t.adaptor for t in all_targets]

    interpreter_constraints = PexInterpreterConstraints.create_from_adaptors(
        adaptors=tuple(all_targets), python_setup=python_setup)

    source_root_stripped_sources = yield [
        Get(SourceRootStrippedSources, HydratedTarget, target_adaptor)
        for target_adaptor in all_targets
    ]

    #TODO(#8420) This way of calculating the entry point works but is a bit hackish.
    entry_point = None
    if hasattr(python_binary_adaptor, 'entry_point'):
        entry_point = python_binary_adaptor.entry_point
    else:
        sources_snapshot = python_binary_adaptor.sources.snapshot
        if len(sources_snapshot.files) == 1:
            target = transitive_hydrated_targets.roots[0]
            output = yield Get(SourceRootStrippedSources, HydratedTarget,
                               target)
            root_filename = output.snapshot.files[0]
            entry_point = PythonBinary.translate_source_path_to_py_module_specifier(
                root_filename)

    stripped_sources_digests = [
        stripped_sources.snapshot.directory_digest
        for stripped_sources in source_root_stripped_sources
    ]
    sources_digest = yield Get(
        Digest,
        DirectoriesToMerge(directories=tuple(stripped_sources_digests)))
    inits_digest = yield Get(InjectedInitDigest, Digest, sources_digest)
    all_input_digests = [sources_digest, inits_digest.directory_digest]
    merged_input_files = yield Get(
        Digest, DirectoriesToMerge,
        DirectoriesToMerge(directories=tuple(all_input_digests)))

    requirements = PexRequirements.create_from_adaptors(all_target_adaptors)
    output_filename = f"{python_binary_adaptor.address.target_name}.pex"

    create_requirements_pex = CreatePex(
        output_filename=output_filename,
        requirements=requirements,
        interpreter_constraints=interpreter_constraints,
        entry_point=entry_point,
        input_files_digest=merged_input_files,
    )

    pex = yield Get(Pex, CreatePex, create_requirements_pex)
    yield CreatedBinary(digest=pex.directory_digest,
                        binary_name=pex.output_filename)
async def setup_lambdex(lambdex: Lambdex) -> LambdexSetup:
    requirements_pex = await Get[Pex](CreatePex(
        output_filename="lambdex.pex",
        requirements=PexRequirements(lambdex.get_requirement_specs()),
        interpreter_constraints=PexInterpreterConstraints(
            lambdex.default_interpreter_constraints),
        entry_point=lambdex.get_entry_point(),
    ))
    return LambdexSetup(requirements_pex=requirements_pex, )
Beispiel #10
0
async def setup_setuptools(setuptools: Setuptools) -> SetuptoolsSetup:
    # Note that this pex has no entrypoint. We use it to run our generated setup.py, which
    # in turn imports from and invokes setuptools.
    requirements_pex = await Get[Pex](CreatePex(
        output_filename="setuptools.pex",
        requirements=PexRequirements(
            requirements=tuple(setuptools.get_requirement_specs())),
        interpreter_constraints=PexInterpreterConstraints(
            constraint_set=tuple(setuptools.default_interpreter_constraints))))
    return SetuptoolsSetup(requirements_pex=requirements_pex, )
Beispiel #11
0
async def setup_coverage(coverage: PytestCoverage) -> CoverageSetup:
    plugin_file_digest = await Get[Digest](InputFilesContent,
                                           get_coverage_plugin_input())
    output_pex_filename = "coverage.pex"
    requirements_pex = await Get[Pex](CreatePex(
        output_filename=output_pex_filename,
        requirements=PexRequirements(coverage.get_requirement_specs()),
        interpreter_constraints=PexInterpreterConstraints(
            coverage.default_interpreter_constraints),
        entry_point=coverage.get_entry_point(),
        input_files_digest=plugin_file_digest,
    ))
    return CoverageSetup(requirements_pex)
Beispiel #12
0
async def lint(
  wrapped_target: Flake8Target,
  flake8: Flake8,
  python_setup: PythonSetup,
  subprocess_encoding_environment: SubprocessEncodingEnvironment,
) -> LintResult:
  if flake8.options.skip:
    return LintResult.noop()

  target = wrapped_target.target

  # 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_adaptors(
    adaptors=[target] if isinstance(target, PythonTargetAdaptor) else [],
    python_setup=python_setup
  )

  config_path: Optional[str] = flake8.options.config
  config_snapshot = await Get[Snapshot](
    PathGlobs(include=tuple([config_path] if config_path else []))
  )
  requirements_pex = await Get[Pex](
    CreatePex(
      output_filename="flake8.pex",
      requirements=PexRequirements(requirements=tuple(flake8.get_requirement_specs())),
      interpreter_constraints=interpreter_constraints,
      entry_point=flake8.get_entry_point(),
    )
  )

  merged_input_files = await Get[Digest](
    DirectoriesToMerge(
      directories=(
        target.sources.snapshot.directory_digest,
        requirements_pex.directory_digest,
        config_snapshot.directory_digest,
      )
    ),
  )
  request = requirements_pex.create_execute_request(
    python_setup=python_setup,
    subprocess_encoding_environment=subprocess_encoding_environment,
    pex_path=f'./flake8.pex',
    pex_args=generate_args(wrapped_target, flake8),
    input_files=merged_input_files,
    description=f'Run Flake8 for {target.address.reference()}',
  )
  result = await Get[FallibleExecuteProcessResult](ExecuteProcessRequest, request)
  return LintResult.from_fallible_execute_process_result(result)
Beispiel #13
0
async def setup(
    request: SetupRequest,
    docformatter: Docformatter,
    python_setup: PythonSetup,
    subprocess_encoding_environment: SubprocessEncodingEnvironment,
) -> Setup:
    adaptors_with_origins = request.formatter.adaptors_with_origins

    requirements_pex = await Get[Pex](CreatePex(
        output_filename="docformatter.pex",
        requirements=PexRequirements(docformatter.get_requirement_specs()),
        interpreter_constraints=PexInterpreterConstraints(
            docformatter.default_interpreter_constraints),
        entry_point=docformatter.get_entry_point(),
    ))

    if request.formatter.prior_formatter_result is None:
        all_source_files = await Get[SourceFiles](AllSourceFilesRequest(
            adaptor_with_origin.adaptor
            for adaptor_with_origin in adaptors_with_origins))
        all_source_files_snapshot = all_source_files.snapshot
    else:
        all_source_files_snapshot = request.formatter.prior_formatter_result

    specified_source_files = await Get[SourceFiles](
        SpecifiedSourceFilesRequest(adaptors_with_origins))

    merged_input_files = await Get[Digest](DirectoriesToMerge(directories=(
        all_source_files_snapshot.directory_digest,
        requirements_pex.directory_digest,
    )), )

    address_references = ", ".join(
        sorted(adaptor_with_origin.adaptor.address.reference()
               for adaptor_with_origin in adaptors_with_origins))

    process_request = requirements_pex.create_execute_request(
        python_setup=python_setup,
        subprocess_encoding_environment=subprocess_encoding_environment,
        pex_path="./docformatter.pex",
        pex_args=generate_args(
            specified_source_files=specified_source_files,
            docformatter=docformatter,
            check_only=request.check_only,
        ),
        input_files=merged_input_files,
        output_files=all_source_files_snapshot.files,
        description=f"Run docformatter for {address_references}",
    )
    return Setup(process_request)
Beispiel #14
0
async def lint(
    wrapped_target: BanditTarget,
    bandit: Bandit,
    python_setup: PythonSetup,
    subprocess_encoding_environment: SubprocessEncodingEnvironment,
) -> LintResult:
    if bandit.options.skip:
        return LintResult.noop()

    target = wrapped_target.target

    # NB: Bandit output depends upon which Python interpreter version it's run with. We ensure that
    # each target runs with its own interpreter constraints. See
    # https://github.com/PyCQA/bandit#under-which-version-of-python-should-i-install-bandit.
    interpreter_constraints = PexInterpreterConstraints.create_from_adaptors(
        adaptors=[target] if isinstance(target, PythonTargetAdaptor) else [],
        python_setup=python_setup)

    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`",
    ))
    requirements_pex = await Get[Pex](CreatePex(
        output_filename="bandit.pex",
        requirements=PexRequirements(
            requirements=tuple(bandit.get_requirement_specs())),
        interpreter_constraints=interpreter_constraints,
        entry_point=bandit.get_entry_point(),
    ))

    merged_input_files = await Get[Digest](DirectoriesToMerge(directories=(
        target.sources.snapshot.directory_digest,
        requirements_pex.directory_digest,
        config_snapshot.directory_digest,
    )), )
    request = requirements_pex.create_execute_request(
        python_setup=python_setup,
        subprocess_encoding_environment=subprocess_encoding_environment,
        pex_path=f'./bandit.pex',
        pex_args=generate_args(wrapped_target, bandit),
        input_files=merged_input_files,
        description=f'Run Bandit for {target.address.reference()}',
    )
    result = await Get[FallibleExecuteProcessResult](ExecuteProcessRequest,
                                                     request)
    return LintResult.from_fallible_execute_process_result(result)
Beispiel #15
0
async def setup_black(black: Black) -> BlackSetup:
    config_path: Optional[str] = black.get_options().config
    config_snapshot = await Get[Snapshot](PathGlobs(include=(config_path, )))
    requirements_pex = await Get[Pex](CreatePex(
        output_filename="black.pex",
        requirements=PexRequirements(
            requirements=tuple(black.get_requirement_specs())),
        interpreter_constraints=PexInterpreterConstraints(
            constraint_set=tuple(black.default_interpreter_constraints)),
        entry_point=black.get_entry_point(),
    ))
    return BlackSetup(
        requirements_pex=requirements_pex,
        config_snapshot=config_snapshot,
        passthrough_args=black.get_args(),
    )
Beispiel #16
0
async def setup_isort(isort: Isort) -> IsortSetup:
    config_path: Optional[List[str]] = isort.get_options().config
    config_snapshot = await Get[Snapshot](PathGlobs(include=config_path or ()))
    requirements_pex = await Get[Pex](CreatePex(
        output_filename="isort.pex",
        requirements=PexRequirements(
            requirements=tuple(isort.get_requirement_specs())),
        interpreter_constraints=PexInterpreterConstraints(
            constraint_set=tuple(isort.default_interpreter_constraints)),
        entry_point=isort.get_entry_point(),
    ))
    return IsortSetup(
        requirements_pex=requirements_pex,
        config_snapshot=config_snapshot,
        passthrough_args=isort.get_args(),
    )
Beispiel #17
0
async def create_pex_from_target_closure(request: CreatePexFromTargetClosure,
                                         python_setup: PythonSetup) -> Pex:
    transitive_hydrated_targets = await Get[TransitiveHydratedTargets](
        BuildFileAddresses, request.build_file_addresses)
    all_targets = transitive_hydrated_targets.closure
    all_target_adaptors = [t.adaptor for t in all_targets]

    interpreter_constraints = PexInterpreterConstraints.create_from_adaptors(
        adaptors=tuple(all_targets), python_setup=python_setup)

    merged_input_files: Optional[Digest] = None
    if request.include_source_files:
        source_root_stripped_sources = await MultiGet(
            Get[SourceRootStrippedSources](HydratedTarget, target_adaptor)
            for target_adaptor in all_targets)

        stripped_sources_digests = [
            stripped_sources.snapshot.directory_digest
            for stripped_sources in source_root_stripped_sources
        ]
        sources_digest = await Get[Digest](
            DirectoriesToMerge(directories=tuple(stripped_sources_digests)))
        inits_digest = await Get[InjectedInitDigest](Digest, sources_digest)
        all_input_digests = [sources_digest, inits_digest.directory_digest]
        merged_input_files = await Get[Digest](
            DirectoriesToMerge,
            DirectoriesToMerge(directories=tuple(all_input_digests)))

    requirements = PexRequirements.create_from_adaptors(
        adaptors=all_target_adaptors,
        additional_requirements=request.additional_requirements)

    create_pex_request = CreatePex(
        output_filename=request.output_filename,
        requirements=requirements,
        interpreter_constraints=interpreter_constraints,
        entry_point=request.entry_point,
        input_files_digest=merged_input_files,
    )

    pex = await Get[Pex](CreatePex, create_pex_request)
    return pex
Beispiel #18
0
async def setup_black(black: Black) -> BlackSetup:
    config_path: Optional[str] = black.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 `--black-config`",
    ))
    requirements_pex = await Get[Pex](CreatePex(
        output_filename="black.pex",
        requirements=PexRequirements(
            requirements=tuple(black.get_requirement_specs())),
        interpreter_constraints=PexInterpreterConstraints(
            constraint_set=tuple(black.default_interpreter_constraints)),
        entry_point=black.get_entry_point(),
    ))
    return BlackSetup(
        requirements_pex=requirements_pex,
        config_snapshot=config_snapshot,
        passthrough_args=tuple(black.options.args),
        skip=black.options.skip,
    )
Beispiel #19
0
async def setup_isort(isort: Isort) -> IsortSetup:
    config_path: Optional[List[str]] = isort.options.config
    config_snapshot = await Get[Snapshot](PathGlobs(
        globs=config_path or (),
        glob_match_error_behavior=GlobMatchErrorBehavior.error,
        conjunction=GlobExpansionConjunction.all_match,
        description_of_origin="the option `--isort-config`",
    ))
    requirements_pex = await Get[Pex](CreatePex(
        output_filename="isort.pex",
        requirements=PexRequirements(
            requirements=tuple(isort.get_requirement_specs())),
        interpreter_constraints=PexInterpreterConstraints(
            constraint_set=tuple(isort.default_interpreter_constraints)),
        entry_point=isort.get_entry_point(),
    ))
    return IsortSetup(
        requirements_pex=requirements_pex,
        config_snapshot=config_snapshot,
        passthrough_args=tuple(isort.options.args),
        skip=isort.options.skip,
    )
Beispiel #20
0
def run_black(
    wrapped_target: FormattablePythonTarget,
    black: Black,
    python_setup: PythonSetup,
    subprocess_encoding_environment: SubprocessEncodingEnvironment,
) -> FmtResult:
    config_path = black.get_options().config
    config_snapshot = yield Get(Snapshot, PathGlobs(include=(config_path, )))

    resolved_requirements_pex = yield Get(
        Pex,
        CreatePex(
            output_filename="black.pex",
            requirements=PexRequirements(
                requirements=tuple(black.get_requirement_specs())),
            interpreter_constraints=PexInterpreterContraints(
                constraint_set=frozenset(
                    black.default_interpreter_constraints)),
            entry_point=black.get_entry_point(),
        ))
    target = wrapped_target.target
    sources_digest = target.sources.snapshot.directory_digest

    all_input_digests = [
        sources_digest,
        resolved_requirements_pex.directory_digest,
        config_snapshot.directory_digest,
    ]
    merged_input_files = yield Get(
        Digest,
        DirectoriesToMerge(directories=tuple(all_input_digests)),
    )

    # The exclude option from Black only works on recursive invocations,
    # so call black with the directories in which the files are present
    # and passing the full file names with the include option
    dirs: Set[str] = set()
    for filename in target.sources.snapshot.files:
        dirs.add(f"{Path(filename).parent}")
    pex_args = tuple(sorted(dirs))
    if config_path:
        pex_args += ("--config", config_path)
    if target.sources.snapshot.files:
        pex_args += ("--include", "|".join(
            re.escape(f) for f in target.sources.snapshot.files))

    request = resolved_requirements_pex.create_execute_request(
        python_setup=python_setup,
        subprocess_encoding_environment=subprocess_encoding_environment,
        pex_path="./black.pex",
        pex_args=pex_args,
        input_files=merged_input_files,
        output_files=target.sources.snapshot.files,
        description=f'Run Black for {target.address.reference()}',
    )

    result = yield Get(ExecuteProcessResult, ExecuteProcessRequest, request)

    yield FmtResult(
        digest=result.output_directory_digest,
        stdout=result.stdout.decode(),
        stderr=result.stderr.decode(),
    )
Beispiel #21
0
async def lint(
    linter: PylintLinter,
    pylint: Pylint,
    python_setup: PythonSetup,
    subprocess_encoding_environment: SubprocessEncodingEnvironment,
) -> LintResult:
    if pylint.options.skip:
        return LintResult.noop()

    adaptors_with_origins = linter.adaptors_with_origins

    # 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.
    hydrated_targets = [
        HydratedTarget(adaptor_with_origin.adaptor)
        for adaptor_with_origin in adaptors_with_origins
    ]
    dependencies = await MultiGet(
        Get[HydratedTarget](Address, dependency)
        for dependency in itertools.chain.from_iterable(
            ht.adaptor.dependencies for ht in hydrated_targets))
    chrooted_python_sources = await Get[ChrootedPythonSources](HydratedTargets(
        [*hydrated_targets, *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_adaptors(
        (adaptor_with_origin.adaptor
         for adaptor_with_origin in adaptors_with_origins),
        python_setup=python_setup,
    )
    requirements_pex = await Get[Pex](CreatePex(
        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(adaptors_with_origins,
                                    strip_source_roots=True))

    address_references = ", ".join(
        sorted(adaptor_with_origin.adaptor.address.reference()
               for adaptor_with_origin in adaptors_with_origins))

    request = requirements_pex.create_execute_request(
        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 for {address_references}",
    )
    result = await Get[FallibleExecuteProcessResult](ExecuteProcessRequest,
                                                     request)
    return LintResult.from_fallible_execute_process_result(result)
Beispiel #22
0
async def lint(
    linter: Flake8Linter,
    flake8: Flake8,
    python_setup: PythonSetup,
    subprocess_encoding_environment: SubprocessEncodingEnvironment,
) -> LintResult:
    if flake8.options.skip:
        return LintResult.noop()

    adaptors_with_origins = linter.adaptors_with_origins

    # 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_adaptors(
        (adaptor_with_origin.adaptor
         for adaptor_with_origin in adaptors_with_origins),
        python_setup=python_setup,
    )
    requirements_pex = await Get[Pex](CreatePex(
        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(
        adaptor_with_origin.adaptor
        for adaptor_with_origin in adaptors_with_origins))
    specified_source_files = await Get[SourceFiles](
        SpecifiedSourceFilesRequest(adaptors_with_origins))

    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(adaptor_with_origin.adaptor.address.reference()
               for adaptor_with_origin in adaptors_with_origins))

    request = requirements_pex.create_execute_request(
        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 for {address_references}",
    )
    result = await Get[FallibleExecuteProcessResult](ExecuteProcessRequest,
                                                     request)
    return LintResult.from_fallible_execute_process_result(result)
Beispiel #23
0
async def run_python_test(
    test_target: PythonTestsAdaptor, pytest: PyTest, python_setup: PythonSetup,
    subprocess_encoding_environment: SubprocessEncodingEnvironment
) -> TestResult:
    """Runs pytest for one target."""

    # TODO(7726): replace this with a proper API to get the `closure` for a
    # TransitiveHydratedTarget.
    transitive_hydrated_targets = await Get(
        TransitiveHydratedTargets, BuildFileAddresses((test_target.address, )))
    all_targets = transitive_hydrated_targets.closure
    all_target_adaptors = tuple(t.adaptor for t in all_targets)

    interpreter_constraints = PexInterpreterConstraints.create_from_adaptors(
        adaptors=tuple(all_target_adaptors), python_setup=python_setup)

    output_pytest_requirements_pex_filename = 'pytest-with-requirements.pex'
    requirements = PexRequirements.create_from_adaptors(
        adaptors=all_target_adaptors,
        additional_requirements=pytest.get_requirement_strings())
    resolved_requirements_pex = await Get(
        Pex,
        CreatePex(
            output_filename=output_pytest_requirements_pex_filename,
            requirements=requirements,
            interpreter_constraints=interpreter_constraints,
            entry_point="pytest:main",
        ))

    # Get the file names for the test_target, adjusted for the source root. This allows us to
    # specify to Pytest which files to test and thus to avoid the test auto-discovery defined by
    # https://pytest.org/en/latest/goodpractices.html#test-discovery. In addition to a performance
    # optimization, this ensures that any transitive sources, such as a test project file named
    # test_fail.py, do not unintentionally end up being run as tests.
    source_root_stripped_test_target_sources = await Get(
        SourceRootStrippedSources, Address, test_target.address.to_address())

    source_root_stripped_sources = await MultiGet(
        Get(SourceRootStrippedSources, HydratedTarget, target_adaptor)
        for target_adaptor in all_targets)

    stripped_sources_digests = tuple(
        stripped_sources.snapshot.directory_digest
        for stripped_sources in source_root_stripped_sources)
    sources_digest = await Get(
        Digest, DirectoriesToMerge(directories=stripped_sources_digests))

    inits_digest = await Get(InjectedInitDigest, Digest, sources_digest)

    merged_input_files = await Get(
        Digest,
        DirectoriesToMerge(directories=(
            sources_digest,
            inits_digest.directory_digest,
            resolved_requirements_pex.directory_digest,
        )),
    )

    test_target_sources_file_names = sorted(
        source_root_stripped_test_target_sources.snapshot.files)
    request = resolved_requirements_pex.create_execute_request(
        python_setup=python_setup,
        subprocess_encoding_environment=subprocess_encoding_environment,
        pex_path=f'./{output_pytest_requirements_pex_filename}',
        pex_args=(*pytest.get_args(), *test_target_sources_file_names),
        input_files=merged_input_files,
        description=f'Run Pytest for {test_target.address.reference()}',
        # TODO(#8584): hook this up to TestRunnerTaskMixin so that we can configure the default timeout
        #  and also use the specified max timeout time.
        timeout_seconds=getattr(test_target, 'timeout', 60))
    result = await Get(FallibleExecuteProcessResult, ExecuteProcessRequest,
                       request)
    return TestResult.from_fallible_execute_process_result(result)
Beispiel #24
0
def run_python_test(
    test_target: PythonTestsAdaptor, pytest: PyTest, python_setup: PythonSetup,
    subprocess_encoding_environment: SubprocessEncodingEnvironment
) -> TestResult:
    """Runs pytest for one target."""

    # TODO(7726): replace this with a proper API to get the `closure` for a
    # TransitiveHydratedTarget.
    transitive_hydrated_targets = yield Get(
        TransitiveHydratedTargets, BuildFileAddresses((test_target.address, )))
    all_targets = transitive_hydrated_targets.closure
    all_target_adaptors = tuple(t.adaptor for t in all_targets)

    interpreter_constraints = PexInterpreterContraints.create_from_adaptors(
        adaptors=tuple(all_target_adaptors), python_setup=python_setup)

    # Produce a pex containing pytest and all transitive 3rdparty requirements.
    output_pytest_requirements_pex_filename = 'pytest-with-requirements.pex'
    requirements = PexRequirements.create_from_adaptors(
        adaptors=all_target_adaptors,
        additional_requirements=pytest.get_requirement_strings())

    resolved_requirements_pex = yield Get(
        Pex,
        CreatePex(
            output_filename=output_pytest_requirements_pex_filename,
            requirements=requirements,
            interpreter_constraints=interpreter_constraints,
            entry_point="pytest:main",
        ))

    # Get the file names for the test_target, adjusted for the source root. This allows us to
    # specify to Pytest which files to test and thus to avoid the test auto-discovery defined by
    # https://pytest.org/en/latest/goodpractices.html#test-discovery. In addition to a performance
    # optimization, this ensures that any transitive sources, such as a test project file named
    # test_fail.py, do not unintentionally end up being run as tests.

    source_root_stripped_test_target_sources = yield Get(
        SourceRootStrippedSources, Address, test_target.address.to_address())

    source_root_stripped_sources = yield [
        Get(SourceRootStrippedSources, HydratedTarget, target_adaptor)
        for target_adaptor in all_targets
    ]

    stripped_sources_digests = [
        stripped_sources.snapshot.directory_digest
        for stripped_sources in source_root_stripped_sources
    ]
    sources_digest = yield Get(
        Digest,
        DirectoriesToMerge(directories=tuple(stripped_sources_digests)),
    )

    inits_digest = yield Get(InjectedInitDigest, Digest, sources_digest)

    all_input_digests = [
        sources_digest,
        inits_digest.directory_digest,
        resolved_requirements_pex.directory_digest,
    ]
    merged_input_files = yield Get(
        Digest,
        DirectoriesToMerge,
        DirectoriesToMerge(directories=tuple(all_input_digests)),
    )

    test_target_sources_file_names = sorted(
        source_root_stripped_test_target_sources.snapshot.files)
    # NB: we use the hardcoded and generic bin name `python`, rather than something dynamic like
    # `sys.executable`, to ensure that the interpreter may be discovered both locally and in remote
    # execution (so long as `env` is populated with a `PATH` env var and `python` is discoverable
    # somewhere on that PATH). This is only used to run the downloaded PEX tool; it is not
    # necessarily the interpreter that PEX will use to execute the generated .pex file.
    request = resolved_requirements_pex.create_execute_request(
        python_setup=python_setup,
        subprocess_encoding_environment=subprocess_encoding_environment,
        pex_path=f'./{output_pytest_requirements_pex_filename}',
        pex_args=test_target_sources_file_names,
        input_files=merged_input_files,
        description=f'Run Pytest for {test_target.address.reference()}',
    )

    result = yield Get(FallibleExecuteProcessResult, ExecuteProcessRequest,
                       request)
    status = Status.SUCCESS if result.exit_code == 0 else Status.FAILURE

    yield TestResult(
        status=status,
        stdout=result.stdout.decode(),
        stderr=result.stderr.decode(),
    )