diff --git a/src/python/pants/backend/awslambda/common/awslambda_common_rules.py b/src/python/pants/backend/awslambda/common/awslambda_common_rules.py index 074cbb16d71..2098a1c52c9 100644 --- a/src/python/pants/backend/awslambda/common/awslambda_common_rules.py +++ b/src/python/pants/backend/awslambda/common/awslambda_common_rules.py @@ -12,11 +12,7 @@ from pants.engine.goal import Goal, GoalSubsystem, LineOriented from pants.engine.rules import goal_rule from pants.engine.selectors import Get, MultiGet -from pants.engine.target import ( - Configuration, - TargetsToValidConfigurations, - TargetsToValidConfigurationsRequest, -) +from pants.engine.target import FieldSet, TargetsToValidFieldSets, TargetsToValidFieldSetsRequest from pants.engine.unions import union @@ -33,7 +29,7 @@ class CreatedAWSLambda: @union -class AWSLambdaConfiguration(Configuration, metaclass=ABCMeta): +class AWSLambdaFieldSet(FieldSet, metaclass=ABCMeta): """The fields necessary to create an AWS Lambda from a target.""" @@ -55,16 +51,16 @@ async def create_awslambda( buildroot: BuildRoot, workspace: Workspace, ) -> AWSLambdaGoal: - targets_to_valid_configs = await Get[TargetsToValidConfigurations]( - TargetsToValidConfigurationsRequest( - AWSLambdaConfiguration, + targets_to_valid_field_sets = await Get[TargetsToValidFieldSets]( + TargetsToValidFieldSetsRequest( + AWSLambdaFieldSet, goal_description=f"the `{options.name}` goal", error_if_no_valid_targets=True, ) ) awslambdas = await MultiGet( - Get[CreatedAWSLambda](AWSLambdaConfiguration, config) - for config in targets_to_valid_configs.configurations + Get[CreatedAWSLambda](AWSLambdaFieldSet, field_set) + for field_set in targets_to_valid_field_sets.field_sets ) merged_digest = await Get[Digest](MergeDigests(awslambda.digest for awslambda in awslambdas)) result = workspace.materialize_directory( diff --git a/src/python/pants/backend/awslambda/python/awslambda_python_rules.py b/src/python/pants/backend/awslambda/python/awslambda_python_rules.py index 39d3859e159..5a9937e73e2 100644 --- a/src/python/pants/backend/awslambda/python/awslambda_python_rules.py +++ b/src/python/pants/backend/awslambda/python/awslambda_python_rules.py @@ -4,7 +4,7 @@ from dataclasses import dataclass from pants.backend.awslambda.common.awslambda_common_rules import ( - AWSLambdaConfiguration, + AWSLambdaFieldSet, CreatedAWSLambda, ) from pants.backend.awslambda.python.lambdex import Lambdex @@ -43,7 +43,7 @@ @dataclass(frozen=True) -class PythonAwsLambdaConfiguration(AWSLambdaConfiguration): +class PythonAwsLambdaFieldSet(AWSLambdaFieldSet): required_fields = (PythonAwsLambdaHandler, PythonAwsLambdaRuntime) handler: PythonAwsLambdaHandler @@ -57,23 +57,23 @@ class LambdexSetup: @named_rule(desc="Create Python AWS Lambda") async def create_python_awslambda( - config: PythonAwsLambdaConfiguration, + field_set: PythonAwsLambdaFieldSet, lambdex_setup: LambdexSetup, python_setup: PythonSetup, subprocess_encoding_environment: SubprocessEncodingEnvironment, ) -> CreatedAWSLambda: # Lambdas typically use the .zip suffix, so we use that instead of .pex. - pex_filename = f"{config.address.target_name}.zip" + pex_filename = f"{field_set.address.target_name}.zip" # We hardcode the platform value to the appropriate one for each AWS Lambda runtime. # (Running the "hello world" lambda in the example code will report the platform, and can be # used to verify correctness of these platform strings.) - py_major, py_minor = config.runtime.to_interpreter_version() + py_major, py_minor = field_set.runtime.to_interpreter_version() platform = f"manylinux2014_x86_64-cp-{py_major}{py_minor}-cp{py_major}{py_minor}m" if (py_major, py_minor) == (2, 7): platform += "u" pex_request = TwoStepPexFromTargetsRequest( PexFromTargetsRequest( - addresses=Addresses([config.address]), + addresses=Addresses([field_set.address]), entry_point=None, output_filename=pex_filename, platforms=PexPlatforms([platform]), @@ -86,7 +86,7 @@ async def create_python_awslambda( ) # NB: Lambdex modifies its input pex in-place, so the input file is also the output file. - lambdex_args = ("build", "-e", config.handler.value, pex_filename) + lambdex_args = ("build", "-e", field_set.handler.value, pex_filename) process = lambdex_setup.requirements_pex.create_process( python_setup=python_setup, subprocess_encoding_environment=subprocess_encoding_environment, @@ -102,7 +102,7 @@ async def create_python_awslambda( return CreatedAWSLambda( digest=result.output_digest, name=pex_filename, - runtime=config.runtime.value, + runtime=field_set.runtime.value, handler="lambdex_handler.handler", ) @@ -126,7 +126,7 @@ def rules(): return [ create_python_awslambda, setup_lambdex, - UnionRule(AWSLambdaConfiguration, PythonAwsLambdaConfiguration), + UnionRule(AWSLambdaFieldSet, PythonAwsLambdaFieldSet), SubsystemRule(Lambdex), *download_pex_bin.rules(), *importable_python_sources.rules(), diff --git a/src/python/pants/backend/awslambda/python/awslambda_python_rules_test.py b/src/python/pants/backend/awslambda/python/awslambda_python_rules_test.py index af4713a1578..8c284b534a8 100644 --- a/src/python/pants/backend/awslambda/python/awslambda_python_rules_test.py +++ b/src/python/pants/backend/awslambda/python/awslambda_python_rules_test.py @@ -7,7 +7,7 @@ from zipfile import ZipFile from pants.backend.awslambda.common.awslambda_common_rules import CreatedAWSLambda -from pants.backend.awslambda.python.awslambda_python_rules import PythonAwsLambdaConfiguration +from pants.backend.awslambda.python.awslambda_python_rules import PythonAwsLambdaFieldSet from pants.backend.awslambda.python.awslambda_python_rules import rules as awslambda_python_rules from pants.backend.awslambda.python.target_types import PythonAWSLambda from pants.backend.python.target_types import PythonLibrary @@ -23,7 +23,7 @@ class TestPythonAWSLambdaCreation(TestBase): @classmethod def rules(cls): - return (*super().rules(), *awslambda_python_rules(), RootRule(PythonAwsLambdaConfiguration)) + return (*super().rules(), *awslambda_python_rules(), RootRule(PythonAwsLambdaFieldSet)) @classmethod def target_types(cls): @@ -34,7 +34,7 @@ def create_python_awslambda(self, addr: str) -> Tuple[str, bytes]: created_awslambda = self.request_single_product( CreatedAWSLambda, Params( - PythonAwsLambdaConfiguration.create(target), + PythonAwsLambdaFieldSet.create(target), create_options_bootstrapper( args=["--backend-packages2=pants.backend.awslambda.python"] ), diff --git a/src/python/pants/backend/python/lint/bandit/rules.py b/src/python/pants/backend/python/lint/bandit/rules.py index f5088768cb1..b18320c8d5c 100644 --- a/src/python/pants/backend/python/lint/bandit/rules.py +++ b/src/python/pants/backend/python/lint/bandit/rules.py @@ -15,7 +15,7 @@ from pants.backend.python.subsystems import python_native_code, subprocess_environment from pants.backend.python.subsystems.subprocess_environment import SubprocessEncodingEnvironment from pants.backend.python.target_types import PythonInterpreterCompatibility, PythonSources -from pants.core.goals.lint import LinterConfiguration, LinterConfigurations, LintResult +from pants.core.goals.lint import LinterFieldSet, LinterFieldSets, LintResult from pants.core.util_rules import determine_source_files, strip_source_roots from pants.core.util_rules.determine_source_files import ( AllSourceFilesRequest, @@ -33,15 +33,15 @@ @dataclass(frozen=True) -class BanditConfiguration(LinterConfiguration): +class BanditFieldSet(LinterFieldSet): required_fields = (PythonSources,) sources: PythonSources compatibility: PythonInterpreterCompatibility -class BanditConfigurations(LinterConfigurations): - config_type = BanditConfiguration +class BanditFieldSets(LinterFieldSets): + field_set_type = BanditFieldSet def generate_args(*, specified_source_files: SourceFiles, bandit: Bandit) -> Tuple[str, ...]: @@ -55,7 +55,7 @@ def generate_args(*, specified_source_files: SourceFiles, bandit: Bandit) -> Tup @named_rule(desc="Lint using Bandit") async def bandit_lint( - configs: BanditConfigurations, + field_sets: BanditFieldSets, bandit: Bandit, python_setup: PythonSetup, subprocess_encoding_environment: SubprocessEncodingEnvironment, @@ -66,7 +66,7 @@ async def bandit_lint( # 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 + (field_set.compatibility for field_set in field_sets), python_setup=python_setup ) requirements_pex = await Get[Pex]( PexRequest( @@ -87,10 +87,12 @@ async def bandit_lint( ) all_source_files = await Get[SourceFiles]( - AllSourceFilesRequest(config.sources for config in configs) + AllSourceFilesRequest(field_set.sources for field_set in field_sets) ) specified_source_files = await Get[SourceFiles]( - SpecifiedSourceFilesRequest((config.sources, config.origin) for config in configs) + SpecifiedSourceFilesRequest( + (field_set.sources, field_set.origin) for field_set in field_sets + ) ) merged_input_files = await Get[Digest]( @@ -99,7 +101,9 @@ async def bandit_lint( ), ) - address_references = ", ".join(sorted(config.address.reference() for config in configs)) + address_references = ", ".join( + sorted(field_set.address.reference() for field_set in field_sets) + ) process = requirements_pex.create_process( python_setup=python_setup, @@ -107,7 +111,7 @@ async def bandit_lint( 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}.", + description=f"Run Bandit on {pluralize(len(field_sets), 'target')}: {address_references}.", ) result = await Get[FallibleProcessResult](Process, process) return LintResult.from_fallible_process_result(result) @@ -117,7 +121,7 @@ def rules(): return [ bandit_lint, SubsystemRule(Bandit), - UnionRule(LinterConfigurations, BanditConfigurations), + UnionRule(LinterFieldSets, BanditFieldSets), *download_pex_bin.rules(), *determine_source_files.rules(), *pex.rules(), diff --git a/src/python/pants/backend/python/lint/bandit/rules_integration_test.py b/src/python/pants/backend/python/lint/bandit/rules_integration_test.py index 53c0ffcf862..b7c7c7d9e0a 100644 --- a/src/python/pants/backend/python/lint/bandit/rules_integration_test.py +++ b/src/python/pants/backend/python/lint/bandit/rules_integration_test.py @@ -3,7 +3,7 @@ from typing import List, Optional -from pants.backend.python.lint.bandit.rules import BanditConfiguration, BanditConfigurations +from pants.backend.python.lint.bandit.rules import BanditFieldSet, BanditFieldSets from pants.backend.python.lint.bandit.rules import rules as bandit_rules from pants.backend.python.target_types import PythonInterpreterCompatibility, PythonLibrary from pants.base.specs import FilesystemLiteralSpec, OriginSpec, SingleAddress @@ -25,7 +25,7 @@ class BanditIntegrationTest(TestBase): @classmethod def rules(cls): - return (*super().rules(), *bandit_rules(), RootRule(BanditConfigurations)) + return (*super().rules(), *bandit_rules(), RootRule(BanditFieldSets)) def make_target_with_origin( self, @@ -63,7 +63,7 @@ def run_bandit( return self.request_single_product( LintResult, Params( - BanditConfigurations(BanditConfiguration.create(tgt) for tgt in targets), + BanditFieldSets(BanditFieldSet.create(tgt) for tgt in targets), create_options_bootstrapper(args=args), ), ) diff --git a/src/python/pants/backend/python/lint/black/rules.py b/src/python/pants/backend/python/lint/black/rules.py index 9bb98be85da..8cd1540ee4b 100644 --- a/src/python/pants/backend/python/lint/black/rules.py +++ b/src/python/pants/backend/python/lint/black/rules.py @@ -7,7 +7,7 @@ from typing import Optional, Tuple from pants.backend.python.lint.black.subsystem import Black -from pants.backend.python.lint.python_fmt import PythonFmtConfigurations +from pants.backend.python.lint.python_fmt import PythonFmtFieldSets from pants.backend.python.rules import download_pex_bin, pex from pants.backend.python.rules.pex import ( Pex, @@ -18,8 +18,8 @@ from pants.backend.python.subsystems import python_native_code, subprocess_environment from pants.backend.python.subsystems.subprocess_environment import SubprocessEncodingEnvironment from pants.backend.python.target_types import PythonSources -from pants.core.goals.fmt import FmtConfiguration, FmtConfigurations, FmtResult -from pants.core.goals.lint import LinterConfigurations, LintResult +from pants.core.goals.fmt import FmtFieldSet, FmtFieldSets, FmtResult +from pants.core.goals.lint import LinterFieldSets, LintResult from pants.core.util_rules import determine_source_files, strip_source_roots from pants.core.util_rules.determine_source_files import ( AllSourceFilesRequest, @@ -37,19 +37,19 @@ @dataclass(frozen=True) -class BlackConfiguration(FmtConfiguration): +class BlackFieldSet(FmtFieldSet): required_fields = (PythonSources,) sources: PythonSources -class BlackConfigurations(FmtConfigurations): - config_type = BlackConfiguration +class BlackFieldSets(FmtFieldSets): + field_set_type = BlackFieldSet @dataclass(frozen=True) class SetupRequest: - configs: BlackConfigurations + field_sets: BlackFieldSets check_only: bool @@ -106,16 +106,18 @@ async def setup( ) ) - if request.configs.prior_formatter_result is None: + if request.field_sets.prior_formatter_result is None: all_source_files = await Get[SourceFiles]( - AllSourceFilesRequest(config.sources for config in request.configs) + AllSourceFilesRequest(field_set.sources for field_set in request.field_sets) ) all_source_files_snapshot = all_source_files.snapshot else: - all_source_files_snapshot = request.configs.prior_formatter_result + all_source_files_snapshot = request.field_sets.prior_formatter_result specified_source_files = await Get[SourceFiles]( - SpecifiedSourceFilesRequest((config.sources, config.origin) for config in request.configs) + SpecifiedSourceFilesRequest( + (field_set.sources, field_set.origin) for field_set in request.field_sets + ) ) merged_input_files = await Get[Digest]( @@ -124,7 +126,9 @@ async def setup( ), ) - address_references = ", ".join(sorted(config.address.reference() for config in request.configs)) + address_references = ", ".join( + sorted(field_set.address.reference() for field_set in request.field_sets) + ) process = requirements_pex.create_process( python_setup=python_setup, @@ -138,26 +142,26 @@ async def setup( input_files=merged_input_files, output_files=all_source_files_snapshot.files, description=( - f"Run Black on {pluralize(len(request.configs), 'target')}: {address_references}." + f"Run Black on {pluralize(len(request.field_sets), 'target')}: {address_references}." ), ) return Setup(process, original_digest=all_source_files_snapshot.digest) @named_rule(desc="Format using Black") -async def black_fmt(configs: BlackConfigurations, black: Black) -> FmtResult: +async def black_fmt(field_sets: BlackFieldSets, black: Black) -> FmtResult: if black.options.skip: return FmtResult.noop() - setup = await Get[Setup](SetupRequest(configs, check_only=False)) + setup = await Get[Setup](SetupRequest(field_sets, check_only=False)) result = await Get[ProcessResult](Process, setup.process) return FmtResult.from_process_result(result, original_digest=setup.original_digest) @named_rule(desc="Lint using Black") -async def black_lint(configs: BlackConfigurations, black: Black) -> LintResult: +async def black_lint(field_sets: BlackFieldSets, black: Black) -> LintResult: if black.options.skip: return LintResult.noop() - setup = await Get[Setup](SetupRequest(configs, check_only=True)) + setup = await Get[Setup](SetupRequest(field_sets, check_only=True)) result = await Get[FallibleProcessResult](Process, setup.process) return LintResult.from_fallible_process_result(result) @@ -168,8 +172,8 @@ def rules(): black_fmt, black_lint, SubsystemRule(Black), - UnionRule(PythonFmtConfigurations, BlackConfigurations), - UnionRule(LinterConfigurations, BlackConfigurations), + UnionRule(PythonFmtFieldSets, BlackFieldSets), + UnionRule(LinterFieldSets, BlackFieldSets), *download_pex_bin.rules(), *determine_source_files.rules(), *pex.rules(), diff --git a/src/python/pants/backend/python/lint/black/rules_integration_test.py b/src/python/pants/backend/python/lint/black/rules_integration_test.py index d971671e331..ba204058c37 100644 --- a/src/python/pants/backend/python/lint/black/rules_integration_test.py +++ b/src/python/pants/backend/python/lint/black/rules_integration_test.py @@ -3,7 +3,7 @@ from typing import List, Optional, Tuple -from pants.backend.python.lint.black.rules import BlackConfiguration, BlackConfigurations +from pants.backend.python.lint.black.rules import BlackFieldSet, BlackFieldSets from pants.backend.python.lint.black.rules import rules as black_rules from pants.backend.python.target_types import PythonLibrary from pants.base.specs import FilesystemLiteralSpec, OriginSpec, SingleAddress @@ -30,7 +30,7 @@ class BlackIntegrationTest(TestBase): @classmethod def rules(cls): - return (*super().rules(), *black_rules(), RootRule(BlackConfigurations)) + return (*super().rules(), *black_rules(), RootRule(BlackFieldSets)) def make_target_with_origin( self, source_files: List[FileContent], *, origin: Optional[OriginSpec] = None, @@ -59,20 +59,21 @@ def run_black( if skip: args.append(f"--black-skip") options_bootstrapper = create_options_bootstrapper(args=args) - configs = [BlackConfiguration.create(tgt) for tgt in targets] + field_sets = [BlackFieldSet.create(tgt) for tgt in targets] lint_result = self.request_single_product( - LintResult, Params(BlackConfigurations(configs), options_bootstrapper) + LintResult, Params(BlackFieldSets(field_sets), options_bootstrapper) ) input_snapshot = self.request_single_product( SourceFiles, Params( - AllSourceFilesRequest(config.sources for config in configs), options_bootstrapper + AllSourceFilesRequest(field_set.sources for field_set in field_sets), + options_bootstrapper, ), ) fmt_result = self.request_single_product( FmtResult, Params( - BlackConfigurations(configs, prior_formatter_result=input_snapshot), + BlackFieldSets(field_sets, prior_formatter_result=input_snapshot), options_bootstrapper, ), ) diff --git a/src/python/pants/backend/python/lint/docformatter/rules.py b/src/python/pants/backend/python/lint/docformatter/rules.py index eb49a755bc3..a6018cb7a87 100644 --- a/src/python/pants/backend/python/lint/docformatter/rules.py +++ b/src/python/pants/backend/python/lint/docformatter/rules.py @@ -5,7 +5,7 @@ from typing import Tuple from pants.backend.python.lint.docformatter.subsystem import Docformatter -from pants.backend.python.lint.python_fmt import PythonFmtConfigurations +from pants.backend.python.lint.python_fmt import PythonFmtFieldSets from pants.backend.python.rules import download_pex_bin, pex from pants.backend.python.rules.pex import ( Pex, @@ -16,8 +16,8 @@ from pants.backend.python.subsystems import python_native_code, subprocess_environment from pants.backend.python.subsystems.subprocess_environment import SubprocessEncodingEnvironment from pants.backend.python.target_types import PythonSources -from pants.core.goals.fmt import FmtConfiguration, FmtConfigurations, FmtResult -from pants.core.goals.lint import LinterConfigurations, LintResult +from pants.core.goals.fmt import FmtFieldSet, FmtFieldSets, FmtResult +from pants.core.goals.lint import LinterFieldSets, LintResult from pants.core.util_rules import determine_source_files, strip_source_roots from pants.core.util_rules.determine_source_files import ( AllSourceFilesRequest, @@ -34,19 +34,19 @@ @dataclass(frozen=True) -class DocformatterConfiguration(FmtConfiguration): +class DocformatterFieldSet(FmtFieldSet): required_fields = (PythonSources,) sources: PythonSources -class DocformatterConfigurations(FmtConfigurations): - config_type = DocformatterConfiguration +class DocformatterFieldSets(FmtFieldSets): + field_set_type = DocformatterFieldSet @dataclass(frozen=True) class SetupRequest: - configs: DocformatterConfigurations + field_sets: DocformatterFieldSets check_only: bool @@ -84,23 +84,27 @@ async def setup( ) ) - if request.configs.prior_formatter_result is None: + if request.field_sets.prior_formatter_result is None: all_source_files = await Get[SourceFiles]( - AllSourceFilesRequest(config.sources for config in request.configs) + AllSourceFilesRequest(field_set.sources for field_set in request.field_sets) ) all_source_files_snapshot = all_source_files.snapshot else: - all_source_files_snapshot = request.configs.prior_formatter_result + all_source_files_snapshot = request.field_sets.prior_formatter_result specified_source_files = await Get[SourceFiles]( - SpecifiedSourceFilesRequest((config.sources, config.origin) for config in request.configs) + SpecifiedSourceFilesRequest( + (field_set.sources, field_set.origin) for field_set in request.field_sets + ) ) merged_input_files = await Get[Digest]( MergeDigests((all_source_files_snapshot.digest, requirements_pex.digest)), ) - address_references = ", ".join(sorted(config.address.reference() for config in request.configs)) + address_references = ", ".join( + sorted(field_set.address.reference() for field_set in request.field_sets) + ) process = requirements_pex.create_process( python_setup=python_setup, @@ -114,7 +118,7 @@ async def setup( input_files=merged_input_files, output_files=all_source_files_snapshot.files, description=( - f"Run Docformatter on {pluralize(len(request.configs), 'target')}: " + f"Run Docformatter on {pluralize(len(request.field_sets), 'target')}: " f"{address_references}." ), ) @@ -123,22 +127,22 @@ async def setup( @named_rule(desc="Format Python docstrings with docformatter") async def docformatter_fmt( - configs: DocformatterConfigurations, docformatter: Docformatter + field_sets: DocformatterFieldSets, docformatter: Docformatter ) -> FmtResult: if docformatter.options.skip: return FmtResult.noop() - setup = await Get[Setup](SetupRequest(configs, check_only=False)) + setup = await Get[Setup](SetupRequest(field_sets, check_only=False)) result = await Get[ProcessResult](Process, setup.process) return FmtResult.from_process_result(result, original_digest=setup.original_digest) @named_rule(desc="Lint Python docstrings with docformatter") async def docformatter_lint( - configs: DocformatterConfigurations, docformatter: Docformatter + field_sets: DocformatterFieldSets, docformatter: Docformatter ) -> LintResult: if docformatter.options.skip: return LintResult.noop() - setup = await Get[Setup](SetupRequest(configs, check_only=True)) + setup = await Get[Setup](SetupRequest(field_sets, check_only=True)) result = await Get[FallibleProcessResult](Process, setup.process) return LintResult.from_fallible_process_result(result) @@ -149,8 +153,8 @@ def rules(): docformatter_fmt, docformatter_lint, SubsystemRule(Docformatter), - UnionRule(PythonFmtConfigurations, DocformatterConfigurations), - UnionRule(LinterConfigurations, DocformatterConfigurations), + UnionRule(PythonFmtFieldSets, DocformatterFieldSets), + UnionRule(LinterFieldSets, DocformatterFieldSets), *download_pex_bin.rules(), *determine_source_files.rules(), *pex.rules(), diff --git a/src/python/pants/backend/python/lint/docformatter/rules_integration_test.py b/src/python/pants/backend/python/lint/docformatter/rules_integration_test.py index 9e14539e8c7..e25ffaece5b 100644 --- a/src/python/pants/backend/python/lint/docformatter/rules_integration_test.py +++ b/src/python/pants/backend/python/lint/docformatter/rules_integration_test.py @@ -3,10 +3,7 @@ from typing import List, Optional, Tuple -from pants.backend.python.lint.docformatter.rules import ( - DocformatterConfiguration, - DocformatterConfigurations, -) +from pants.backend.python.lint.docformatter.rules import DocformatterFieldSet, DocformatterFieldSets from pants.backend.python.lint.docformatter.rules import rules as docformatter_rules from pants.backend.python.target_types import PythonLibrary from pants.base.specs import FilesystemLiteralSpec, OriginSpec, SingleAddress @@ -30,7 +27,7 @@ class DocformatterIntegrationTest(TestBase): @classmethod def rules(cls): - return (*super().rules(), *docformatter_rules(), RootRule(DocformatterConfigurations)) + return (*super().rules(), *docformatter_rules(), RootRule(DocformatterFieldSets)) def make_target_with_origin( self, source_files: List[FileContent], *, origin: Optional[OriginSpec] = None, @@ -55,20 +52,21 @@ def run_docformatter( if skip: args.append(f"--docformatter-skip") options_bootstrapper = create_options_bootstrapper(args=args) - configs = [DocformatterConfiguration.create(tgt) for tgt in targets] + field_sets = [DocformatterFieldSet.create(tgt) for tgt in targets] lint_result = self.request_single_product( - LintResult, Params(DocformatterConfigurations(configs), options_bootstrapper) + LintResult, Params(DocformatterFieldSets(field_sets), options_bootstrapper) ) input_snapshot = self.request_single_product( SourceFiles, Params( - AllSourceFilesRequest(config.sources for config in configs), options_bootstrapper + AllSourceFilesRequest(field_set.sources for field_set in field_sets), + options_bootstrapper, ), ) fmt_result = self.request_single_product( FmtResult, Params( - DocformatterConfigurations(configs, prior_formatter_result=input_snapshot), + DocformatterFieldSets(field_sets, prior_formatter_result=input_snapshot), options_bootstrapper, ), ) diff --git a/src/python/pants/backend/python/lint/flake8/rules.py b/src/python/pants/backend/python/lint/flake8/rules.py index acced8c98dc..b9a4151bb2e 100644 --- a/src/python/pants/backend/python/lint/flake8/rules.py +++ b/src/python/pants/backend/python/lint/flake8/rules.py @@ -15,7 +15,7 @@ from pants.backend.python.subsystems import python_native_code, subprocess_environment from pants.backend.python.subsystems.subprocess_environment import SubprocessEncodingEnvironment from pants.backend.python.target_types import PythonInterpreterCompatibility, PythonSources -from pants.core.goals.lint import LinterConfiguration, LinterConfigurations, LintResult +from pants.core.goals.lint import LinterFieldSet, LinterFieldSets, LintResult from pants.core.util_rules import determine_source_files, strip_source_roots from pants.core.util_rules.determine_source_files import ( AllSourceFilesRequest, @@ -33,15 +33,15 @@ @dataclass(frozen=True) -class Flake8Configuration(LinterConfiguration): +class Flake8FieldSet(LinterFieldSet): required_fields = (PythonSources,) sources: PythonSources compatibility: PythonInterpreterCompatibility -class Flake8Configurations(LinterConfigurations): - config_type = Flake8Configuration +class Flake8FieldSets(LinterFieldSets): + field_set_type = Flake8FieldSet def generate_args(*, specified_source_files: SourceFiles, flake8: Flake8) -> Tuple[str, ...]: @@ -55,7 +55,7 @@ def generate_args(*, specified_source_files: SourceFiles, flake8: Flake8) -> Tup @named_rule(desc="Lint using Flake8") async def flake8_lint( - configs: Flake8Configurations, + field_sets: Flake8FieldSets, flake8: Flake8, python_setup: PythonSetup, subprocess_encoding_environment: SubprocessEncodingEnvironment, @@ -67,7 +67,7 @@ async def flake8_lint( # 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 + (field_set.compatibility for field_set in field_sets), python_setup ) requirements_pex = await Get[Pex]( PexRequest( @@ -88,10 +88,12 @@ async def flake8_lint( ) all_source_files = await Get[SourceFiles]( - AllSourceFilesRequest(config.sources for config in configs) + AllSourceFilesRequest(field_set.sources for field_set in field_sets) ) specified_source_files = await Get[SourceFiles]( - SpecifiedSourceFilesRequest((config.sources, config.origin) for config in configs) + SpecifiedSourceFilesRequest( + (field_set.sources, field_set.origin) for field_set in field_sets + ) ) merged_input_files = await Get[Digest]( @@ -100,7 +102,9 @@ async def flake8_lint( ), ) - address_references = ", ".join(sorted(config.address.reference() for config in configs)) + address_references = ", ".join( + sorted(field_set.address.reference() for field_set in field_sets) + ) process = requirements_pex.create_process( python_setup=python_setup, @@ -108,7 +112,7 @@ async def flake8_lint( 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}.", + description=f"Run Flake8 on {pluralize(len(field_sets), 'target')}: {address_references}.", ) result = await Get[FallibleProcessResult](Process, process) return LintResult.from_fallible_process_result(result) @@ -118,7 +122,7 @@ def rules(): return [ flake8_lint, SubsystemRule(Flake8), - UnionRule(LinterConfigurations, Flake8Configurations), + UnionRule(LinterFieldSets, Flake8FieldSets), *download_pex_bin.rules(), *determine_source_files.rules(), *pex.rules(), diff --git a/src/python/pants/backend/python/lint/flake8/rules_integration_test.py b/src/python/pants/backend/python/lint/flake8/rules_integration_test.py index e7a1e0ceb6c..102ff144cf9 100644 --- a/src/python/pants/backend/python/lint/flake8/rules_integration_test.py +++ b/src/python/pants/backend/python/lint/flake8/rules_integration_test.py @@ -3,7 +3,7 @@ from typing import List, Optional -from pants.backend.python.lint.flake8.rules import Flake8Configuration, Flake8Configurations +from pants.backend.python.lint.flake8.rules import Flake8FieldSet, Flake8FieldSets from pants.backend.python.lint.flake8.rules import rules as flake8_rules from pants.backend.python.target_types import PythonInterpreterCompatibility, PythonLibrary from pants.base.specs import FilesystemLiteralSpec, OriginSpec, SingleAddress @@ -26,7 +26,7 @@ class Flake8IntegrationTest(TestBase): @classmethod def rules(cls): - return (*super().rules(), *flake8_rules(), RootRule(Flake8Configurations)) + return (*super().rules(), *flake8_rules(), RootRule(Flake8FieldSets)) def make_target_with_origin( self, @@ -64,7 +64,7 @@ def run_flake8( return self.request_single_product( LintResult, Params( - Flake8Configurations(Flake8Configuration.create(tgt) for tgt in targets), + Flake8FieldSets(Flake8FieldSet.create(tgt) for tgt in targets), create_options_bootstrapper(args=args), ), ) diff --git a/src/python/pants/backend/python/lint/isort/rules.py b/src/python/pants/backend/python/lint/isort/rules.py index 02d2fa4091a..ce0526fecaa 100644 --- a/src/python/pants/backend/python/lint/isort/rules.py +++ b/src/python/pants/backend/python/lint/isort/rules.py @@ -5,7 +5,7 @@ from typing import List, Optional, Tuple from pants.backend.python.lint.isort.subsystem import Isort -from pants.backend.python.lint.python_fmt import PythonFmtConfigurations +from pants.backend.python.lint.python_fmt import PythonFmtFieldSets from pants.backend.python.rules import download_pex_bin, pex from pants.backend.python.rules.pex import ( Pex, @@ -16,8 +16,8 @@ from pants.backend.python.subsystems import python_native_code, subprocess_environment from pants.backend.python.subsystems.subprocess_environment import SubprocessEncodingEnvironment from pants.backend.python.target_types import PythonSources -from pants.core.goals.fmt import FmtConfiguration, FmtConfigurations, FmtResult -from pants.core.goals.lint import LinterConfigurations, LintResult +from pants.core.goals.fmt import FmtFieldSet, FmtFieldSets, FmtResult +from pants.core.goals.lint import LinterFieldSets, LintResult from pants.core.util_rules import determine_source_files, strip_source_roots from pants.core.util_rules.determine_source_files import ( AllSourceFilesRequest, @@ -36,19 +36,19 @@ @dataclass(frozen=True) -class IsortConfiguration(FmtConfiguration): +class IsortFieldSet(FmtFieldSet): required_fields = (PythonSources,) sources: PythonSources -class IsortConfigurations(FmtConfigurations): - config_type = IsortConfiguration +class IsortFieldSets(FmtFieldSets): + field_set_type = IsortFieldSet @dataclass(frozen=True) class SetupRequest: - configs: IsortConfigurations + field_sets: IsortFieldSets check_only: bool @@ -99,16 +99,18 @@ async def setup( ) ) - if request.configs.prior_formatter_result is None: + if request.field_sets.prior_formatter_result is None: all_source_files = await Get[SourceFiles]( - AllSourceFilesRequest(config.sources for config in request.configs) + AllSourceFilesRequest(field_set.sources for field_set in request.field_sets) ) all_source_files_snapshot = all_source_files.snapshot else: - all_source_files_snapshot = request.configs.prior_formatter_result + all_source_files_snapshot = request.field_sets.prior_formatter_result specified_source_files = await Get[SourceFiles]( - SpecifiedSourceFilesRequest((config.sources, config.origin) for config in request.configs) + SpecifiedSourceFilesRequest( + (field_set.sources, field_set.origin) for field_set in request.field_sets + ) ) merged_input_files = await Get[Digest]( @@ -117,7 +119,9 @@ async def setup( ), ) - address_references = ", ".join(sorted(config.address.reference() for config in request.configs)) + address_references = ", ".join( + sorted(field_set.address.reference() for field_set in request.field_sets) + ) process = requirements_pex.create_process( python_setup=python_setup, @@ -131,26 +135,26 @@ async def setup( input_files=merged_input_files, output_files=all_source_files_snapshot.files, description=( - f"Run isort on {pluralize(len(request.configs), 'target')}: {address_references}." + f"Run isort on {pluralize(len(request.field_sets), 'target')}: {address_references}." ), ) return Setup(process, original_digest=all_source_files_snapshot.digest) @named_rule(desc="Format using isort") -async def isort_fmt(configs: IsortConfigurations, isort: Isort) -> FmtResult: +async def isort_fmt(field_sets: IsortFieldSets, isort: Isort) -> FmtResult: if isort.options.skip: return FmtResult.noop() - setup = await Get[Setup](SetupRequest(configs, check_only=False)) + setup = await Get[Setup](SetupRequest(field_sets, check_only=False)) result = await Get[ProcessResult](Process, setup.process) return FmtResult.from_process_result(result, original_digest=setup.original_digest) @named_rule(desc="Lint using isort") -async def isort_lint(configs: IsortConfigurations, isort: Isort) -> LintResult: +async def isort_lint(field_sets: IsortFieldSets, isort: Isort) -> LintResult: if isort.options.skip: return LintResult.noop() - setup = await Get[Setup](SetupRequest(configs, check_only=True)) + setup = await Get[Setup](SetupRequest(field_sets, check_only=True)) result = await Get[FallibleProcessResult](Process, setup.process) return LintResult.from_fallible_process_result(result) @@ -161,8 +165,8 @@ def rules(): isort_fmt, isort_lint, SubsystemRule(Isort), - UnionRule(PythonFmtConfigurations, IsortConfigurations), - UnionRule(LinterConfigurations, IsortConfigurations), + UnionRule(PythonFmtFieldSets, IsortFieldSets), + UnionRule(LinterFieldSets, IsortFieldSets), *download_pex_bin.rules(), *determine_source_files.rules(), *pex.rules(), diff --git a/src/python/pants/backend/python/lint/isort/rules_integration_test.py b/src/python/pants/backend/python/lint/isort/rules_integration_test.py index 58bd7cdf30c..43c1a21c3bb 100644 --- a/src/python/pants/backend/python/lint/isort/rules_integration_test.py +++ b/src/python/pants/backend/python/lint/isort/rules_integration_test.py @@ -3,7 +3,7 @@ from typing import List, Optional, Tuple -from pants.backend.python.lint.isort.rules import IsortConfiguration, IsortConfigurations +from pants.backend.python.lint.isort.rules import IsortFieldSet, IsortFieldSets from pants.backend.python.lint.isort.rules import rules as isort_rules from pants.backend.python.target_types import PythonLibrary from pants.base.specs import FilesystemLiteralSpec, OriginSpec, SingleAddress @@ -37,7 +37,7 @@ class IsortIntegrationTest(TestBase): @classmethod def rules(cls): - return (*super().rules(), *isort_rules(), RootRule(IsortConfigurations)) + return (*super().rules(), *isort_rules(), RootRule(IsortFieldSets)) def make_target_with_origin( self, source_files: List[FileContent], *, origin: Optional[OriginSpec] = None, @@ -66,20 +66,21 @@ def run_isort( if skip: args.append(f"--isort-skip") options_bootstrapper = create_options_bootstrapper(args=args) - configs = [IsortConfiguration.create(tgt) for tgt in targets] + field_sets = [IsortFieldSet.create(tgt) for tgt in targets] lint_result = self.request_single_product( - LintResult, Params(IsortConfigurations(configs), options_bootstrapper) + LintResult, Params(IsortFieldSets(field_sets), options_bootstrapper) ) input_snapshot = self.request_single_product( SourceFiles, Params( - AllSourceFilesRequest(config.sources for config in configs), options_bootstrapper + AllSourceFilesRequest(field_set.sources for field_set in field_sets), + options_bootstrapper, ), ) fmt_result = self.request_single_product( FmtResult, Params( - IsortConfigurations(configs, prior_formatter_result=input_snapshot), + IsortFieldSets(field_sets, prior_formatter_result=input_snapshot), options_bootstrapper, ), ) diff --git a/src/python/pants/backend/python/lint/pylint/rules.py b/src/python/pants/backend/python/lint/pylint/rules.py index b4ccdc3ef55..e728540fa44 100644 --- a/src/python/pants/backend/python/lint/pylint/rules.py +++ b/src/python/pants/backend/python/lint/pylint/rules.py @@ -16,7 +16,7 @@ from pants.backend.python.subsystems import python_native_code, subprocess_environment from pants.backend.python.subsystems.subprocess_environment import SubprocessEncodingEnvironment from pants.backend.python.target_types import PythonInterpreterCompatibility, PythonSources -from pants.core.goals.lint import LinterConfiguration, LinterConfigurations, LintResult +from pants.core.goals.lint import LinterFieldSet, LinterFieldSets, LintResult from pants.core.util_rules import determine_source_files, strip_source_roots from pants.core.util_rules.determine_source_files import SourceFiles, SpecifiedSourceFilesRequest from pants.engine.addresses import Addresses @@ -32,7 +32,7 @@ @dataclass(frozen=True) -class PylintConfiguration(LinterConfiguration): +class PylintFieldSet(LinterFieldSet): required_fields = (PythonSources,) sources: PythonSources @@ -40,8 +40,8 @@ class PylintConfiguration(LinterConfiguration): compatibility: PythonInterpreterCompatibility -class PylintConfigurations(LinterConfigurations): - config_type = PylintConfiguration +class PylintFieldSets(LinterFieldSets): + field_set_type = PylintFieldSet def generate_args(*, specified_source_files: SourceFiles, pylint: Pylint) -> Tuple[str, ...]: @@ -55,7 +55,7 @@ def generate_args(*, specified_source_files: SourceFiles, pylint: Pylint) -> Tup @named_rule(desc="Lint using Pylint") async def pylint_lint( - configs: PylintConfigurations, + field_sets: PylintFieldSets, pylint: Pylint, python_setup: PythonSetup, subprocess_encoding_environment: SubprocessEncodingEnvironment, @@ -66,9 +66,9 @@ async def pylint_lint( # 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 ()) + for field_set in field_sets: + addresses.append(field_set.address) + addresses.extend(field_set.dependencies.value or ()) targets = await Get[Targets](Addresses(addresses)) prepared_python_sources = await Get[ImportablePythonSources](Targets, targets) @@ -76,7 +76,7 @@ async def pylint_lint( # 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 + (field_set.compatibility for field_set in field_sets), python_setup ) requirements_pex = await Get[Pex]( PexRequest( @@ -108,11 +108,14 @@ async def pylint_lint( specified_source_files = await Get[SourceFiles]( SpecifiedSourceFilesRequest( - ((config.sources, config.origin) for config in configs), strip_source_roots=True + ((field_set.sources, field_set.origin) for field_set in field_sets), + strip_source_roots=True, ) ) - address_references = ", ".join(sorted(config.address.reference() for config in configs)) + address_references = ", ".join( + sorted(field_set.address.reference() for field_set in field_sets) + ) process = requirements_pex.create_process( python_setup=python_setup, @@ -120,7 +123,7 @@ async def pylint_lint( 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}.", + 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) @@ -130,7 +133,7 @@ def rules(): return [ pylint_lint, SubsystemRule(Pylint), - UnionRule(LinterConfigurations, PylintConfigurations), + UnionRule(LinterFieldSets, PylintFieldSets), *download_pex_bin.rules(), *determine_source_files.rules(), *pex.rules(), diff --git a/src/python/pants/backend/python/lint/pylint/rules_integration_test.py b/src/python/pants/backend/python/lint/pylint/rules_integration_test.py index 8d984997e57..200b12d9636 100644 --- a/src/python/pants/backend/python/lint/pylint/rules_integration_test.py +++ b/src/python/pants/backend/python/lint/pylint/rules_integration_test.py @@ -5,7 +5,7 @@ from textwrap import dedent from typing import List, Optional -from pants.backend.python.lint.pylint.rules import PylintConfiguration, PylintConfigurations +from pants.backend.python.lint.pylint.rules import PylintFieldSet, PylintFieldSets from pants.backend.python.lint.pylint.rules import rules as pylint_rules from pants.backend.python.target_types import PythonInterpreterCompatibility, PythonLibrary from pants.backend.python.targets.python_library import PythonLibrary as PythonLibraryV1 @@ -45,7 +45,7 @@ def rules(cls): return ( *super().rules(), *pylint_rules(), - RootRule(PylintConfigurations), + RootRule(PylintFieldSets), RootRule(HydratedTargets), ) @@ -98,7 +98,7 @@ def run_pylint( return self.request_single_product( LintResult, Params( - PylintConfigurations(PylintConfiguration.create(tgt) for tgt in targets), + PylintFieldSets(PylintFieldSet.create(tgt) for tgt in targets), create_options_bootstrapper(args=args), ), ) diff --git a/src/python/pants/backend/python/lint/python_fmt.py b/src/python/pants/backend/python/lint/python_fmt.py index d85e50f8d5a..bea91bb5f21 100644 --- a/src/python/pants/backend/python/lint/python_fmt.py +++ b/src/python/pants/backend/python/lint/python_fmt.py @@ -5,12 +5,7 @@ from typing import Iterable, List, Type from pants.backend.python.target_types import PythonSources -from pants.core.goals.fmt import ( - FmtConfigurations, - FmtResult, - LanguageFmtResults, - LanguageFmtTargets, -) +from pants.core.goals.fmt import FmtFieldSets, FmtResult, LanguageFmtResults, LanguageFmtTargets from pants.core.util_rules.determine_source_files import AllSourceFilesRequest, SourceFiles from pants.engine.fs import Digest, Snapshot from pants.engine.rules import rule @@ -24,7 +19,7 @@ class PythonFmtTargets(LanguageFmtTargets): @union -class PythonFmtConfigurations: +class PythonFmtFieldSets: pass @@ -42,15 +37,15 @@ async def format_python_target( prior_formatter_result = original_sources.snapshot results: List[FmtResult] = [] - config_collection_types: Iterable[Type[FmtConfigurations]] = union_membership.union_rules[ - PythonFmtConfigurations + field_set_collection_types: Iterable[Type[FmtFieldSets]] = union_membership.union_rules[ + PythonFmtFieldSets ] - for config_collection_type in config_collection_types: + for field_set_collection_type in field_set_collection_types: result = await Get[FmtResult]( - PythonFmtConfigurations, - config_collection_type( + PythonFmtFieldSets, + field_set_collection_type( ( - config_collection_type.config_type.create(target_with_origin) + field_set_collection_type.field_set_type.create(target_with_origin) for target_with_origin in targets_with_origins ), prior_formatter_result=prior_formatter_result, diff --git a/src/python/pants/backend/python/lint/python_fmt_integration_test.py b/src/python/pants/backend/python/lint/python_fmt_integration_test.py index 2645a2390ef..248c902f77c 100644 --- a/src/python/pants/backend/python/lint/python_fmt_integration_test.py +++ b/src/python/pants/backend/python/lint/python_fmt_integration_test.py @@ -3,9 +3,9 @@ from typing import List, Optional -from pants.backend.python.lint.black.rules import BlackConfigurations +from pants.backend.python.lint.black.rules import BlackFieldSets from pants.backend.python.lint.black.rules import rules as black_rules -from pants.backend.python.lint.isort.rules import IsortConfigurations +from pants.backend.python.lint.isort.rules import IsortFieldSets from pants.backend.python.lint.isort.rules import rules as isort_rules from pants.backend.python.lint.python_fmt import PythonFmtTargets, format_python_target from pants.backend.python.target_types import PythonLibrary @@ -29,8 +29,8 @@ def rules(cls): *black_rules(), *isort_rules(), RootRule(PythonFmtTargets), - RootRule(BlackConfigurations), - RootRule(IsortConfigurations), + RootRule(BlackFieldSets), + RootRule(IsortFieldSets), ) def run_black_and_isort( diff --git a/src/python/pants/backend/python/rules/pytest_runner.py b/src/python/pants/backend/python/rules/pytest_runner.py index 5f4bb2f57df..6c57985ffba 100644 --- a/src/python/pants/backend/python/rules/pytest_runner.py +++ b/src/python/pants/backend/python/rules/pytest_runner.py @@ -28,7 +28,7 @@ PythonTestsSources, PythonTestsTimeout, ) -from pants.core.goals.test import TestConfiguration, TestDebugRequest, TestOptions, TestResult +from pants.core.goals.test import TestDebugRequest, TestFieldSet, TestOptions, TestResult from pants.core.util_rules.determine_source_files import SourceFiles, SpecifiedSourceFilesRequest from pants.engine.addresses import Addresses from pants.engine.fs import ( @@ -51,7 +51,7 @@ @dataclass(frozen=True) -class PythonTestConfiguration(TestConfiguration): +class PythonTestFieldSet(TestFieldSet): required_fields = (PythonTestsSources,) sources: PythonTestsSources @@ -74,7 +74,7 @@ class TestTargetSetup: @rule async def setup_pytest_for_target( - config: PythonTestConfiguration, + field_set: PythonTestFieldSet, pytest: PyTest, test_options: TestOptions, python_setup: PythonSetup, @@ -82,7 +82,7 @@ async def setup_pytest_for_target( # TODO: Rather than consuming the TestOptions subsystem, the TestRunner should pass on coverage # configuration via #7490. - test_addresses = Addresses((config.address,)) + test_addresses = Addresses((field_set.address,)) transitive_targets = await Get[TransitiveTargets](Addresses, test_addresses) all_targets = transitive_targets.closure @@ -148,7 +148,7 @@ async def setup_pytest_for_target( # Get the file names for the test_target so that we can specify to Pytest precisely which files # to test, rather than using auto-discovery. specified_source_files_request = SpecifiedSourceFilesRequest( - [(config.sources, config.origin)], strip_source_roots=True + [(field_set.sources, field_set.origin)], strip_source_roots=True ) # TODO(John Sirois): Support exploiting concurrency better: @@ -203,7 +203,7 @@ async def setup_pytest_for_target( coverage_args = [ "--cov-report=", # To not generate any output. https://pytest-cov.readthedocs.io/en/latest/config.html ] - for package in config.coverage.determine_packages_to_cover( + for package in field_set.coverage.determine_packages_to_cover( specified_source_files=specified_source_files ): coverage_args.extend(["--cov", package]) @@ -213,7 +213,7 @@ async def setup_pytest_for_target( test_runner_pex=test_runner_pex, args=(*pytest.options.args, *coverage_args, *specified_source_file_names), input_files_digest=merged_input_files, - timeout_seconds=config.timeout.calculate_from_global_options(pytest), + timeout_seconds=field_set.timeout.calculate_from_global_options(pytest), xml_dir=pytest.options.junit_xml_dir, junit_family=pytest.options.junit_family, ) @@ -221,7 +221,7 @@ async def setup_pytest_for_target( @named_rule(desc="Run pytest") async def run_python_test( - config: PythonTestConfiguration, + field_set: PythonTestFieldSet, test_setup: TestTargetSetup, python_setup: PythonSetup, subprocess_encoding_environment: SubprocessEncodingEnvironment, @@ -231,7 +231,7 @@ async def run_python_test( """Runs pytest for one target.""" add_opts = [f"--color={'yes' if global_options.options.colors else 'no'}"] if test_setup.xml_dir: - test_results_file = f"{config.address.path_safe_spec}.xml" + test_results_file = f"{field_set.address.path_safe_spec}.xml" add_opts.extend( (f"--junitxml={test_results_file}", f"-o junit_family={test_setup.junit_family}",) ) @@ -248,7 +248,7 @@ async def run_python_test( pex_args=test_setup.args, input_files=test_setup.input_files_digest, output_directories=tuple(output_dirs) if output_dirs else None, - description=f"Run Pytest for {config.address.reference()}", + description=f"Run Pytest for {field_set.address.reference()}", timeout_seconds=test_setup.timeout_seconds, env=env, ) @@ -259,7 +259,7 @@ async def run_python_test( coverage_snapshot = await Get[Snapshot]( SnapshotSubset(result.output_digest, PathGlobs([".coverage"])) ) - coverage_data = PytestCoverageData(config.address, coverage_snapshot.digest) + coverage_data = PytestCoverageData(field_set.address, coverage_snapshot.digest) xml_results_digest = None if test_setup.xml_dir: @@ -290,7 +290,7 @@ def rules(): run_python_test, debug_python_test, setup_pytest_for_target, - UnionRule(TestConfiguration, PythonTestConfiguration), + UnionRule(TestFieldSet, PythonTestFieldSet), SubsystemRule(PyTest), SubsystemRule(PythonSetup), ] diff --git a/src/python/pants/backend/python/rules/pytest_runner_integration_test.py b/src/python/pants/backend/python/rules/pytest_runner_integration_test.py index ce33c2b51aa..00999c03faf 100644 --- a/src/python/pants/backend/python/rules/pytest_runner_integration_test.py +++ b/src/python/pants/backend/python/rules/pytest_runner_integration_test.py @@ -14,7 +14,7 @@ pytest_runner, ) from pants.backend.python.rules.pytest_coverage import CoverageConfigRequest, create_coverage_config -from pants.backend.python.rules.pytest_runner import PythonTestConfiguration +from pants.backend.python.rules.pytest_runner import PythonTestFieldSet from pants.backend.python.subsystems import python_native_code, subprocess_environment from pants.backend.python.target_types import PythonLibrary, PythonRequirementLibrary, PythonTests from pants.backend.python.targets.python_library import PythonLibrary as PythonLibraryV1 @@ -128,7 +128,7 @@ def rules(cls): *subprocess_environment.rules(), SubsystemRule(TestOptions), RootRule(CoverageConfigRequest), - RootRule(PythonTestConfiguration), + RootRule(PythonTestFieldSet), ) def run_pytest( @@ -148,7 +148,7 @@ def run_pytest( origin = SingleAddress(directory=address.spec_path, name=address.target_name) tgt = PythonTests({}, address=address) params = Params( - PythonTestConfiguration.create(TargetWithOrigin(tgt, origin)), options_bootstrapper + PythonTestFieldSet.create(TargetWithOrigin(tgt, origin)), options_bootstrapper ) test_result = self.request_single_product(TestResult, params) debug_request = self.request_single_product(TestDebugRequest, params) diff --git a/src/python/pants/backend/python/rules/python_create_binary.py b/src/python/pants/backend/python/rules/python_create_binary.py index 1c830acf645..7ed994155db 100644 --- a/src/python/pants/backend/python/rules/python_create_binary.py +++ b/src/python/pants/backend/python/rules/python_create_binary.py @@ -21,7 +21,7 @@ ) from pants.backend.python.target_types import PythonPlatforms as PythonPlatformsField from pants.backend.python.targets.python_binary import PythonBinary -from pants.core.goals.binary import BinaryConfiguration, CreatedBinary +from pants.core.goals.binary import BinaryFieldSet, CreatedBinary from pants.core.util_rules.determine_source_files import AllSourceFilesRequest, SourceFiles from pants.engine.addresses import Addresses from pants.engine.rules import rule @@ -30,7 +30,7 @@ @dataclass(frozen=True) -class PythonBinaryConfiguration(BinaryConfiguration): +class PythonBinaryFieldSet(BinaryFieldSet): required_fields = (PythonEntryPoint, PythonBinarySources) sources: PythonBinarySources @@ -62,13 +62,13 @@ def generate_additional_args(self) -> Tuple[str, ...]: @rule -async def create_python_binary(config: PythonBinaryConfiguration) -> CreatedBinary: +async def create_python_binary(field_set: PythonBinaryFieldSet) -> CreatedBinary: entry_point: Optional[str] - if config.entry_point.value is not None: - entry_point = config.entry_point.value + if field_set.entry_point.value is not None: + entry_point = field_set.entry_point.value else: source_files = await Get[SourceFiles]( - AllSourceFilesRequest([config.sources], strip_source_roots=True) + AllSourceFilesRequest([field_set.sources], strip_source_roots=True) ) # NB: `PythonBinarySources` enforces that we have 0-1 sources. if len(source_files.files) == 1: @@ -77,15 +77,15 @@ async def create_python_binary(config: PythonBinaryConfiguration) -> CreatedBina else: entry_point = None - output_filename = f"{config.address.target_name}.pex" + output_filename = f"{field_set.address.target_name}.pex" two_step_pex = await Get[TwoStepPex]( TwoStepPexFromTargetsRequest( PexFromTargetsRequest( - addresses=Addresses([config.address]), + addresses=Addresses([field_set.address]), entry_point=entry_point, - platforms=PexPlatforms.create_from_platforms_field(config.platforms), + platforms=PexPlatforms.create_from_platforms_field(field_set.platforms), output_filename=output_filename, - additional_args=config.generate_additional_args(), + additional_args=field_set.generate_additional_args(), ) ) ) @@ -94,4 +94,4 @@ async def create_python_binary(config: PythonBinaryConfiguration) -> CreatedBina def rules(): - return [create_python_binary, UnionRule(BinaryConfiguration, PythonBinaryConfiguration)] + return [create_python_binary, UnionRule(BinaryFieldSet, PythonBinaryFieldSet)] diff --git a/src/python/pants/core/goals/binary.py b/src/python/pants/core/goals/binary.py index fc4f624b808..5c08cea3785 100644 --- a/src/python/pants/core/goals/binary.py +++ b/src/python/pants/core/goals/binary.py @@ -12,16 +12,12 @@ from pants.engine.goal import Goal, GoalSubsystem, LineOriented from pants.engine.rules import goal_rule from pants.engine.selectors import Get, MultiGet -from pants.engine.target import ( - Configuration, - TargetsToValidConfigurations, - TargetsToValidConfigurationsRequest, -) +from pants.engine.target import FieldSet, TargetsToValidFieldSets, TargetsToValidFieldSetsRequest from pants.engine.unions import union @union -class BinaryConfiguration(Configuration, metaclass=ABCMeta): +class BinaryFieldSet(FieldSet, metaclass=ABCMeta): """The fields necessary to create a binary from a target.""" @@ -37,7 +33,7 @@ class BinaryOptions(LineOriented, GoalSubsystem): name = "binary" - required_union_implementations = (BinaryConfiguration,) + required_union_implementations = (BinaryFieldSet,) class Binary(Goal): @@ -52,16 +48,16 @@ async def create_binary( distdir: DistDir, buildroot: BuildRoot, ) -> Binary: - targets_to_valid_configs = await Get[TargetsToValidConfigurations]( - TargetsToValidConfigurationsRequest( - BinaryConfiguration, + targets_to_valid_field_sets = await Get[TargetsToValidFieldSets]( + TargetsToValidFieldSetsRequest( + BinaryFieldSet, goal_description=f"the `{options.name}` goal", error_if_no_valid_targets=True, ) ) binaries = await MultiGet( - Get[CreatedBinary](BinaryConfiguration, config) - for config in targets_to_valid_configs.configurations + Get[CreatedBinary](BinaryFieldSet, field_set) + for field_set in targets_to_valid_field_sets.field_sets ) merged_digest = await Get[Digest](MergeDigests(binary.digest for binary in binaries)) result = workspace.materialize_directory( diff --git a/src/python/pants/core/goals/fmt.py b/src/python/pants/core/goals/fmt.py index bb89f579f0b..23cc3d8b4a3 100644 --- a/src/python/pants/core/goals/fmt.py +++ b/src/python/pants/core/goals/fmt.py @@ -6,7 +6,7 @@ from dataclasses import dataclass from typing import ClassVar, Iterable, List, Optional, Tuple, Type -from pants.core.goals.lint import LinterConfiguration +from pants.core.goals.lint import LinterFieldSet from pants.core.util_rules.filter_empty_sources import TargetsWithSources, TargetsWithSourcesRequest from pants.engine.collection import Collection from pants.engine.console import Console @@ -53,23 +53,23 @@ def did_change(self) -> bool: return self.output != self.input -class FmtConfiguration(LinterConfiguration, metaclass=ABCMeta): +class FmtFieldSet(LinterFieldSet, metaclass=ABCMeta): """The fields necessary for a particular auto-formatter to work with a target.""" -class FmtConfigurations(Collection[FmtConfiguration]): - """A collection of Configurations for a particular formatter, e.g. a collection of - `IsortConfiguration`s.""" +class FmtFieldSets(Collection[FmtFieldSet]): + """A collection of `FieldSet`s for a particular formatter, e.g. a collection of + `IsortFieldSet`s.""" - config_type: ClassVar[Type[FmtConfiguration]] + field_set_type: ClassVar[Type[FmtFieldSet]] def __init__( self, - configs: Iterable[FmtConfiguration], + field_sets: Iterable[FmtFieldSet], *, prior_formatter_result: Optional[Snapshot] = None ) -> None: - super().__init__(configs) + super().__init__(field_sets) self.prior_formatter_result = prior_formatter_result diff --git a/src/python/pants/core/goals/lint.py b/src/python/pants/core/goals/lint.py index f0850047156..75e410a4598 100644 --- a/src/python/pants/core/goals/lint.py +++ b/src/python/pants/core/goals/lint.py @@ -6,8 +6,8 @@ from typing import ClassVar, Iterable, Type, TypeVar from pants.core.util_rules.filter_empty_sources import ( - ConfigurationsWithSources, - ConfigurationsWithSourcesRequest, + FieldSetsWithSources, + FieldSetsWithSourcesRequest, ) from pants.engine.collection import Collection from pants.engine.console import Console @@ -15,7 +15,7 @@ from pants.engine.process import FallibleProcessResult from pants.engine.rules import goal_rule from pants.engine.selectors import Get, MultiGet -from pants.engine.target import ConfigurationWithOrigin, Sources, TargetsWithOrigins +from pants.engine.target import FieldSetWithOrigin, Sources, TargetsWithOrigins from pants.engine.unions import UnionMembership, union @@ -38,21 +38,21 @@ def from_fallible_process_result(process_result: FallibleProcessResult,) -> "Lin ) -class LinterConfiguration(ConfigurationWithOrigin, metaclass=ABCMeta): +class LinterFieldSet(FieldSetWithOrigin, metaclass=ABCMeta): """The fields necessary for a particular linter to work with a target.""" sources: Sources -C = TypeVar("C", bound="LinterConfiguration") +_FS = TypeVar("_FS", bound="LinterFieldSet") @union -class LinterConfigurations(Collection[C]): - """A collection of Configurations for a particular linter, e.g. a collection of - `Flake8Configuration`s.""" +class LinterFieldSets(Collection[_FS]): + """A collection of `FieldSet`s for a particular linter, e.g. a collection of + `Flake8FieldSet`s.""" - config_type: ClassVar[Type[C]] + field_set_type: ClassVar[Type[_FS]] class LintOptions(GoalSubsystem): @@ -60,7 +60,7 @@ class LintOptions(GoalSubsystem): name = "lint" - required_union_implementations = (LinterConfigurations,) + required_union_implementations = (LinterFieldSets,) @classmethod def register_options(cls, register) -> None: @@ -97,43 +97,43 @@ async def lint( options: LintOptions, union_membership: UnionMembership, ) -> Lint: - config_collection_types: Iterable[Type[LinterConfigurations]] = union_membership.union_rules[ - LinterConfigurations + field_set_collection_types: Iterable[Type[LinterFieldSets]] = union_membership.union_rules[ + LinterFieldSets ] - config_collections: Iterable[LinterConfigurations] = tuple( - config_collection_type( - config_collection_type.config_type.create(target_with_origin) + field_set_collections: Iterable[LinterFieldSets] = tuple( + field_set_collection_type( + field_set_collection_type.field_set_type.create(target_with_origin) for target_with_origin in targets_with_origins - if config_collection_type.config_type.is_valid(target_with_origin.target) + if field_set_collection_type.field_set_type.is_valid(target_with_origin.target) ) - for config_collection_type in config_collection_types + for field_set_collection_type in field_set_collection_types ) - config_collections_with_sources: Iterable[ConfigurationsWithSources] = await MultiGet( - Get[ConfigurationsWithSources](ConfigurationsWithSourcesRequest(config_collection)) - for config_collection in config_collections + field_set_collections_with_sources: Iterable[FieldSetsWithSources] = await MultiGet( + Get[FieldSetsWithSources](FieldSetsWithSourcesRequest(field_set_collection)) + for field_set_collection in field_set_collections ) - # NB: We must convert back the generic ConfigurationsWithSources objects back into their - # corresponding LinterConfigurations, e.g. back to IsortConfigurations, in order for the union - # rule to work. - valid_config_collections: Iterable[LinterConfigurations] = tuple( - config_collection_cls(config_collection) - for config_collection_cls, config_collection in zip( - config_collection_types, config_collections_with_sources + # NB: We must convert back the generic FieldSetsWithSources objects back into their + # corresponding LinterFieldSets, e.g. back to IsortFieldSets, in order for the union rule to + # work. + valid_field_set_collections: Iterable[LinterFieldSets] = tuple( + field_set_collection_cls(field_set_collection) + for field_set_collection_cls, field_set_collection in zip( + field_set_collection_types, field_set_collections_with_sources ) - if config_collection + if field_set_collection ) if options.values.per_target_caching: results = await MultiGet( - Get[LintResult](LinterConfigurations, config_collection.__class__([config])) - for config_collection in valid_config_collections - for config in config_collection + Get[LintResult](LinterFieldSets, field_set_collection.__class__([field_set])) + for field_set_collection in valid_field_set_collections + for field_set in field_set_collection ) else: results = await MultiGet( - Get[LintResult](LinterConfigurations, config_collection) - for config_collection in valid_config_collections + Get[LintResult](LinterFieldSets, field_set_collection) + for field_set_collection in valid_field_set_collections ) if not results: diff --git a/src/python/pants/core/goals/lint_test.py b/src/python/pants/core/goals/lint_test.py index 6a73b8316e1..cfaf9d582fb 100644 --- a/src/python/pants/core/goals/lint_test.py +++ b/src/python/pants/core/goals/lint_test.py @@ -7,15 +7,15 @@ from pants.base.specs import SingleAddress from pants.core.goals.lint import ( Lint, - LinterConfiguration, - LinterConfigurations, + LinterFieldSet, + LinterFieldSets, LintOptions, LintResult, lint, ) from pants.core.util_rules.filter_empty_sources import ( - ConfigurationsWithSources, - ConfigurationsWithSourcesRequest, + FieldSetsWithSources, + FieldSetsWithSourcesRequest, ) from pants.engine.addresses import Address from pants.engine.target import Sources, Target, TargetsWithOrigins, TargetWithOrigin @@ -29,12 +29,12 @@ class MockTarget(Target): core_fields = (Sources,) -class MockLinterConfiguration(LinterConfiguration): +class MockLinterFieldSet(LinterFieldSet): required_fields = (Sources,) -class MockLinterConfigurations(LinterConfigurations, metaclass=ABCMeta): - config_type = MockLinterConfiguration +class MockLinterFieldSets(LinterFieldSets, metaclass=ABCMeta): + field_set_type = MockLinterFieldSet @staticmethod @abstractmethod @@ -52,7 +52,7 @@ def lint_result(self) -> LintResult: return LintResult(self.exit_code(addresses), self.stdout(addresses), "") -class SuccessfulConfigurations(MockLinterConfigurations): +class SuccessfulFieldSets(MockLinterFieldSets): @staticmethod def exit_code(_: Iterable[Address]) -> int: return 0 @@ -62,7 +62,7 @@ def stdout(addresses: Iterable[Address]) -> str: return f"Successful linter: {', '.join(str(address) for address in addresses)}" -class FailingConfigurations(MockLinterConfigurations): +class FailingFieldSets(MockLinterFieldSets): @staticmethod def exit_code(_: Iterable[Address]) -> int: return 1 @@ -72,7 +72,7 @@ def stdout(addresses: Iterable[Address]) -> str: return f"Failing linter: {', '.join(str(address) for address in addresses)}" -class ConditionallySucceedsConfigurations(MockLinterConfigurations): +class ConditionallySucceedsFieldSets(MockLinterFieldSets): @staticmethod def exit_code(addresses: Iterable[Address]) -> int: if any(address.target_name == "bad" for address in addresses): @@ -88,12 +88,12 @@ class InvalidField(Sources): pass -class InvalidConfiguration(MockLinterConfiguration): +class InvalidFieldSet(MockLinterFieldSet): required_fields = (InvalidField,) -class InvalidConfigurations(MockLinterConfigurations): - config_type = InvalidConfiguration +class InvalidFieldSets(MockLinterFieldSets): + field_set_type = InvalidFieldSet @staticmethod def exit_code(_: Iterable[Address]) -> int: @@ -117,13 +117,13 @@ def make_target_with_origin(address: Optional[Address] = None) -> TargetWithOrig @staticmethod def run_lint_rule( *, - config_collection_types: List[Type[LinterConfigurations]], + field_set_collection_types: List[Type[LinterFieldSets]], targets: List[TargetWithOrigin], per_target_caching: bool, include_sources: bool = True, ) -> Tuple[int, str]: console = MockConsole(use_colors=False) - union_membership = UnionMembership({LinterConfigurations: config_collection_types}) + union_membership = UnionMembership({LinterFieldSets: field_set_collection_types}) result: Lint = run_rule( lint, rule_args=[ @@ -135,14 +135,14 @@ def run_lint_rule( mock_gets=[ MockGet( product_type=LintResult, - subject_type=LinterConfigurations, - mock=lambda config_collection: config_collection.lint_result, + subject_type=LinterFieldSets, + mock=lambda field_set_collection: field_set_collection.lint_result, ), MockGet( - product_type=ConfigurationsWithSources, - subject_type=ConfigurationsWithSourcesRequest, - mock=lambda configs: ConfigurationsWithSources( - configs if include_sources else () + product_type=FieldSetsWithSources, + subject_type=FieldSetsWithSourcesRequest, + mock=lambda field_sets: FieldSetsWithSources( + field_sets if include_sources else () ), ), ], @@ -153,7 +153,7 @@ def run_lint_rule( def test_empty_target_noops(self) -> None: def assert_noops(per_target_caching: bool) -> None: exit_code, stdout = self.run_lint_rule( - config_collection_types=[FailingConfigurations], + field_set_collection_types=[FailingFieldSets], targets=[self.make_target_with_origin()], per_target_caching=per_target_caching, include_sources=False, @@ -167,7 +167,7 @@ def assert_noops(per_target_caching: bool) -> None: def test_invalid_target_noops(self) -> None: def assert_noops(per_target_caching: bool) -> None: exit_code, stdout = self.run_lint_rule( - config_collection_types=[InvalidConfigurations], + field_set_collection_types=[InvalidFieldSets], targets=[self.make_target_with_origin()], per_target_caching=per_target_caching, ) @@ -183,12 +183,12 @@ def test_single_target_with_one_linter(self) -> None: def assert_expected(per_target_caching: bool) -> None: exit_code, stdout = self.run_lint_rule( - config_collection_types=[FailingConfigurations], + field_set_collection_types=[FailingFieldSets], targets=[target_with_origin], per_target_caching=per_target_caching, ) - assert exit_code == FailingConfigurations.exit_code([address]) - assert stdout.strip() == FailingConfigurations.stdout([address]) + assert exit_code == FailingFieldSets.exit_code([address]) + assert stdout.strip() == FailingFieldSets.stdout([address]) assert_expected(per_target_caching=False) assert_expected(per_target_caching=True) @@ -199,14 +199,14 @@ def test_single_target_with_multiple_linters(self) -> None: def assert_expected(per_target_caching: bool) -> None: exit_code, stdout = self.run_lint_rule( - config_collection_types=[SuccessfulConfigurations, FailingConfigurations], + field_set_collection_types=[SuccessfulFieldSets, FailingFieldSets], targets=[target_with_origin], per_target_caching=per_target_caching, ) - assert exit_code == FailingConfigurations.exit_code([address]) + assert exit_code == FailingFieldSets.exit_code([address]) assert stdout.splitlines() == [ - SuccessfulConfigurations.stdout([address]), - FailingConfigurations.stdout([address]), + SuccessfulFieldSets.stdout([address]), + FailingFieldSets.stdout([address]), ] assert_expected(per_target_caching=False) @@ -218,24 +218,22 @@ def test_multiple_targets_with_one_linter(self) -> None: def get_stdout(*, per_target_caching: bool) -> str: exit_code, stdout = self.run_lint_rule( - config_collection_types=[ConditionallySucceedsConfigurations], + field_set_collection_types=[ConditionallySucceedsFieldSets], targets=[ self.make_target_with_origin(good_address), self.make_target_with_origin(bad_address), ], per_target_caching=per_target_caching, ) - assert exit_code == ConditionallySucceedsConfigurations.exit_code([bad_address]) + assert exit_code == ConditionallySucceedsFieldSets.exit_code([bad_address]) return stdout stdout = get_stdout(per_target_caching=False) - assert stdout.strip() == ConditionallySucceedsConfigurations.stdout( - [good_address, bad_address] - ) + assert stdout.strip() == ConditionallySucceedsFieldSets.stdout([good_address, bad_address]) stdout = get_stdout(per_target_caching=True) assert stdout.splitlines() == [ - ConditionallySucceedsConfigurations.stdout([address]) + ConditionallySucceedsFieldSets.stdout([address]) for address in [good_address, bad_address] ] @@ -245,28 +243,25 @@ def test_multiple_targets_with_multiple_linters(self) -> None: def get_stdout(*, per_target_caching: bool) -> str: exit_code, stdout = self.run_lint_rule( - config_collection_types=[ - ConditionallySucceedsConfigurations, - SuccessfulConfigurations, - ], + field_set_collection_types=[ConditionallySucceedsFieldSets, SuccessfulFieldSets,], targets=[ self.make_target_with_origin(good_address), self.make_target_with_origin(bad_address), ], per_target_caching=per_target_caching, ) - assert exit_code == ConditionallySucceedsConfigurations.exit_code([bad_address]) + assert exit_code == ConditionallySucceedsFieldSets.exit_code([bad_address]) return stdout stdout = get_stdout(per_target_caching=False) assert stdout.splitlines() == [ - config_collection.stdout([good_address, bad_address]) - for config_collection in [ConditionallySucceedsConfigurations, SuccessfulConfigurations] + field_set_collection.stdout([good_address, bad_address]) + for field_set_collection in [ConditionallySucceedsFieldSets, SuccessfulFieldSets] ] stdout = get_stdout(per_target_caching=True) assert stdout.splitlines() == [ - config_collection.stdout([address]) - for config_collection in [ConditionallySucceedsConfigurations, SuccessfulConfigurations] + field_set_collection.stdout([address]) + for field_set_collection in [ConditionallySucceedsFieldSets, SuccessfulFieldSets] for address in [good_address, bad_address] ] diff --git a/src/python/pants/core/goals/run.py b/src/python/pants/core/goals/run.py index 20892a30890..2079bc5fcee 100644 --- a/src/python/pants/core/goals/run.py +++ b/src/python/pants/core/goals/run.py @@ -4,14 +4,14 @@ from pathlib import PurePath from pants.base.build_root import BuildRoot -from pants.core.goals.binary import BinaryConfiguration, CreatedBinary +from pants.core.goals.binary import BinaryFieldSet, CreatedBinary from pants.engine.console import Console from pants.engine.fs import DirectoryToMaterialize, Workspace from pants.engine.goal import Goal, GoalSubsystem from pants.engine.interactive_runner import InteractiveProcessRequest, InteractiveRunner from pants.engine.rules import goal_rule from pants.engine.selectors import Get -from pants.engine.target import TargetsToValidConfigurations, TargetsToValidConfigurationsRequest +from pants.engine.target import TargetsToValidFieldSets, TargetsToValidFieldSetsRequest from pants.option.custom_types import shell_str from pants.option.global_options import GlobalOptions from pants.util.contextutil import temporary_dir @@ -22,8 +22,8 @@ class RunOptions(GoalSubsystem): name = "run" - # NB: To be runnable, there must be a BinaryConfiguration that works with the target. - required_union_implementations = (BinaryConfiguration,) + # NB: To be runnable, there must be a BinaryFieldSet that works with the target. + required_union_implementations = (BinaryFieldSet,) @classmethod def register_options(cls, register) -> None: @@ -51,16 +51,16 @@ async def run( options: RunOptions, global_options: GlobalOptions, ) -> Run: - targets_to_valid_configs = await Get[TargetsToValidConfigurations]( - TargetsToValidConfigurationsRequest( - BinaryConfiguration, + targets_to_valid_field_sets = await Get[TargetsToValidFieldSets]( + TargetsToValidFieldSetsRequest( + BinaryFieldSet, goal_description=f"the `{options.name}` goal", error_if_no_valid_targets=True, - expect_single_config=True, + expect_single_field_set=True, ) ) - config = targets_to_valid_configs.configurations[0] - binary = await Get[CreatedBinary](BinaryConfiguration, config) + field_set = targets_to_valid_field_sets.field_sets[0] + binary = await Get[CreatedBinary](BinaryFieldSet, field_set) workdir = global_options.options.pants_workdir with temporary_dir(root_dir=workdir, cleanup=True) as tmpdir: @@ -69,7 +69,7 @@ async def run( DirectoryToMaterialize(binary.digest, path_prefix=path_relative_to_build_root) ) - console.write_stdout(f"Running target: {config.address}\n") + console.write_stdout(f"Running target: {field_set.address}\n") full_path = PurePath(tmpdir, binary.binary_name).as_posix() run_request = InteractiveProcessRequest( argv=(full_path, *options.values.args), run_in_workspace=True, @@ -79,14 +79,14 @@ async def run( result = runner.run_local_interactive_process(run_request) exit_code = result.process_exit_code if result.process_exit_code == 0: - console.write_stdout(f"{config.address} ran successfully.\n") + console.write_stdout(f"{field_set.address} ran successfully.\n") else: console.write_stderr( - f"{config.address} failed with code {result.process_exit_code}!\n" + f"{field_set.address} failed with code {result.process_exit_code}!\n" ) except Exception as e: - console.write_stderr(f"Exception when attempting to run {config.address}: {e!r}\n") + console.write_stderr(f"Exception when attempting to run {field_set.address}: {e!r}\n") exit_code = -1 return Run(exit_code) diff --git a/src/python/pants/core/goals/run_test.py b/src/python/pants/core/goals/run_test.py index 07edc5ebd52..0b4e39f098e 100644 --- a/src/python/pants/core/goals/run_test.py +++ b/src/python/pants/core/goals/run_test.py @@ -5,15 +5,15 @@ from pants.base.build_root import BuildRoot from pants.base.specs import SingleAddress -from pants.core.goals.binary import BinaryConfiguration, CreatedBinary +from pants.core.goals.binary import BinaryFieldSet, CreatedBinary from pants.core.goals.run import Run, RunOptions, run from pants.engine.addresses import Address from pants.engine.fs import Digest, FileContent, InputFilesContent, Workspace from pants.engine.interactive_runner import InteractiveProcessRequest, InteractiveRunner from pants.engine.target import ( Target, - TargetsToValidConfigurations, - TargetsToValidConfigurationsRequest, + TargetsToValidFieldSets, + TargetsToValidFieldSetsRequest, TargetWithOrigin, ) from pants.option.global_options import GlobalOptions @@ -41,7 +41,7 @@ def single_target_run( workspace = Workspace(self.scheduler) interactive_runner = InteractiveRunner(self.scheduler) - class TestBinaryConfiguration(BinaryConfiguration): + class TestBinaryFieldSet(BinaryFieldSet): required_fields = () class TestBinaryTarget(Target): @@ -53,7 +53,7 @@ class TestBinaryTarget(Target): target_with_origin = TargetWithOrigin( target, SingleAddress(address.spec_path, address.target_name) ) - config = TestBinaryConfiguration.create(target) + field_set = TestBinaryFieldSet.create(target) res = run_rule( run, @@ -67,13 +67,13 @@ class TestBinaryTarget(Target): ], mock_gets=[ MockGet( - product_type=TargetsToValidConfigurations, - subject_type=TargetsToValidConfigurationsRequest, - mock=lambda _: TargetsToValidConfigurations({target_with_origin: [config]}), + product_type=TargetsToValidFieldSets, + subject_type=TargetsToValidFieldSetsRequest, + mock=lambda _: TargetsToValidFieldSets({target_with_origin: [field_set]}), ), MockGet( product_type=CreatedBinary, - subject_type=TestBinaryConfiguration, + subject_type=TestBinaryFieldSet, mock=lambda _: self.create_mock_binary(program_text), ), ], diff --git a/src/python/pants/core/goals/test.py b/src/python/pants/core/goals/test.py index 49ff5780ec4..154cc4e012d 100644 --- a/src/python/pants/core/goals/test.py +++ b/src/python/pants/core/goals/test.py @@ -11,8 +11,8 @@ from pants.base.exiter import PANTS_FAILED_EXIT_CODE, PANTS_SUCCEEDED_EXIT_CODE from pants.core.util_rules.filter_empty_sources import ( - ConfigurationsWithSources, - ConfigurationsWithSourcesRequest, + FieldSetsWithSources, + FieldSetsWithSourcesRequest, ) from pants.engine import desktop from pants.engine.addresses import Address @@ -25,10 +25,10 @@ from pants.engine.rules import goal_rule, rule from pants.engine.selectors import Get, MultiGet from pants.engine.target import ( - ConfigurationWithOrigin, + FieldSetWithOrigin, Sources, - TargetsToValidConfigurations, - TargetsToValidConfigurationsRequest, + TargetsToValidFieldSets, + TargetsToValidFieldSetsRequest, ) from pants.engine.unions import UnionMembership, union @@ -77,7 +77,7 @@ class TestDebugRequest: @union -class TestConfiguration(ConfigurationWithOrigin, metaclass=ABCMeta): +class TestFieldSet(FieldSetWithOrigin, metaclass=ABCMeta): """The fields necessary to run tests on a target.""" sources: Sources @@ -88,8 +88,8 @@ class TestConfiguration(ConfigurationWithOrigin, metaclass=ABCMeta): # NB: This is only used for the sake of coordinator_of_tests. Consider inlining that rule so that # we can remove this wrapper type. @dataclass(frozen=True) -class WrappedTestConfiguration: - config: TestConfiguration +class WrappedTestFieldSet: + field_set: TestFieldSet @dataclass(frozen=True) @@ -162,7 +162,7 @@ class TestOptions(GoalSubsystem): name = "test" - required_union_implementations = (TestConfiguration,) + required_union_implementations = (TestFieldSet,) # Prevent this class from being detected by pytest as a test class. __test__ = False @@ -207,34 +207,34 @@ async def run_tests( union_membership: UnionMembership, ) -> Test: if options.values.debug: - targets_to_valid_configs = await Get[TargetsToValidConfigurations]( - TargetsToValidConfigurationsRequest( - TestConfiguration, + targets_to_valid_field_sets = await Get[TargetsToValidFieldSets]( + TargetsToValidFieldSetsRequest( + TestFieldSet, goal_description="`test --debug`", error_if_no_valid_targets=True, - expect_single_config=True, + expect_single_field_set=True, ) ) - config = targets_to_valid_configs.configurations[0] - logger.info(f"Starting test in debug mode: {config.address.reference()}") - request = await Get[TestDebugRequest](TestConfiguration, config) + field_set = targets_to_valid_field_sets.field_sets[0] + logger.info(f"Starting test in debug mode: {field_set.address.reference()}") + request = await Get[TestDebugRequest](TestFieldSet, field_set) debug_result = interactive_runner.run_local_interactive_process(request.ipr) return Test(debug_result.process_exit_code) - targets_to_valid_configs = await Get[TargetsToValidConfigurations]( - TargetsToValidConfigurationsRequest( - TestConfiguration, + targets_to_valid_field_sets = await Get[TargetsToValidFieldSets]( + TargetsToValidFieldSetsRequest( + TestFieldSet, goal_description=f"the `{options.name}` goal", error_if_no_valid_targets=False, ) ) - configs_with_sources = await Get[ConfigurationsWithSources]( - ConfigurationsWithSourcesRequest(targets_to_valid_configs.configurations) + field_sets_with_sources = await Get[FieldSetsWithSources]( + FieldSetsWithSourcesRequest(targets_to_valid_field_sets.field_sets) ) results = await MultiGet( - Get[AddressAndTestResult](WrappedTestConfiguration(config)) - for config in configs_with_sources + Get[AddressAndTestResult](WrappedTestFieldSet(field_set)) + for field_set in field_sets_with_sources ) did_any_fail = False @@ -306,19 +306,19 @@ async def run_tests( @rule -async def coordinator_of_tests(wrapped_config: WrappedTestConfiguration) -> AddressAndTestResult: - config = wrapped_config.config +async def coordinator_of_tests(wrapped_field_set: WrappedTestFieldSet) -> AddressAndTestResult: + field_set = wrapped_field_set.field_set # TODO(#6004): when streaming to live TTY, rely on V2 UI for this information. When not a # live TTY, periodically dump heavy hitters to stderr. See # https://github.com/pantsbuild/pants/issues/6004#issuecomment-492699898. - logger.info(f"Starting tests: {config.address.reference()}") - result = await Get[TestResult](TestConfiguration, config) + logger.info(f"Starting tests: {field_set.address.reference()}") + result = await Get[TestResult](TestFieldSet, field_set) logger.info( f"Tests {'succeeded' if result.status == Status.SUCCESS else 'failed'}: " - f"{config.address.reference()}" + f"{field_set.address.reference()}" ) - return AddressAndTestResult(config.address, result) + return AddressAndTestResult(field_set.address, result) def rules(): diff --git a/src/python/pants/core/goals/test_test.py b/src/python/pants/core/goals/test_test.py index 09e2a19a1bd..409c8f7e382 100644 --- a/src/python/pants/core/goals/test_test.py +++ b/src/python/pants/core/goals/test_test.py @@ -14,16 +14,16 @@ FilesystemCoverageReport, Status, Test, - TestConfiguration, TestDebugRequest, + TestFieldSet, TestOptions, TestResult, - WrappedTestConfiguration, + WrappedTestFieldSet, run_tests, ) from pants.core.util_rules.filter_empty_sources import ( - ConfigurationsWithSources, - ConfigurationsWithSourcesRequest, + FieldSetsWithSources, + FieldSetsWithSourcesRequest, ) from pants.engine.addresses import Address from pants.engine.fs import EMPTY_DIGEST, Digest, FileContent, InputFilesContent, Workspace @@ -31,8 +31,8 @@ from pants.engine.target import ( Sources, Target, - TargetsToValidConfigurations, - TargetsToValidConfigurationsRequest, + TargetsToValidFieldSets, + TargetsToValidFieldSetsRequest, TargetWithOrigin, ) from pants.engine.unions import UnionMembership @@ -45,7 +45,7 @@ class MockTarget(Target): core_fields = (Sources,) -class MockTestConfiguration(TestConfiguration, metaclass=ABCMeta): +class MockTestFieldSet(TestFieldSet, metaclass=ABCMeta): required_fields = (Sources,) @staticmethod @@ -72,7 +72,7 @@ def test_result(self) -> TestResult: ) -class SuccessfulConfiguration(MockTestConfiguration): +class SuccessfulFieldSet(MockTestFieldSet): @staticmethod def status(_: Address) -> Status: return Status.SUCCESS @@ -82,7 +82,7 @@ def stdout(address: Address) -> str: return f"Successful test target: Passed for {address}!" -class ConditionallySucceedsConfiguration(MockTestConfiguration): +class ConditionallySucceedsFieldSet(MockTestFieldSet): @staticmethod def status(address: Address) -> Status: return Status.FAILURE if address.target_name == "bad" else Status.SUCCESS @@ -126,7 +126,7 @@ def make_target_with_origin(address: Optional[Address] = None) -> TargetWithOrig def run_test_rule( self, *, - config: Type[TestConfiguration], + field_set: Type[TestFieldSet], targets: List[TargetWithOrigin], debug: bool = False, include_sources: bool = True, @@ -136,47 +136,52 @@ def run_test_rule( options = create_goal_subsystem(TestOptions, debug=debug, run_coverage=False) interactive_runner = InteractiveRunner(self.scheduler) workspace = Workspace(self.scheduler) - union_membership = UnionMembership({TestConfiguration: [config]}) + union_membership = UnionMembership({TestFieldSet: [field_set]}) - def mock_find_valid_configs( - _: TargetsToValidConfigurationsRequest, - ) -> TargetsToValidConfigurations: + def mock_find_valid_field_sets( + _: TargetsToValidFieldSetsRequest, + ) -> TargetsToValidFieldSets: if not valid_targets: - return TargetsToValidConfigurations({}) - return TargetsToValidConfigurations( - {tgt_with_origin: [config.create(tgt_with_origin)] for tgt_with_origin in targets} + return TargetsToValidFieldSets({}) + return TargetsToValidFieldSets( + { + tgt_with_origin: [field_set.create(tgt_with_origin)] + for tgt_with_origin in targets + } ) def mock_coordinator_of_tests( - wrapped_config: WrappedTestConfiguration, + wrapped_field_set: WrappedTestFieldSet, ) -> AddressAndTestResult: - config = cast(MockTestConfiguration, wrapped_config.config) - return AddressAndTestResult(address=config.address, test_result=config.test_result) + field_set = cast(MockTestFieldSet, wrapped_field_set.field_set) + return AddressAndTestResult( + address=field_set.address, test_result=field_set.test_result + ) result: Test = run_rule( run_tests, rule_args=[console, options, interactive_runner, workspace, union_membership], mock_gets=[ MockGet( - product_type=TargetsToValidConfigurations, - subject_type=TargetsToValidConfigurationsRequest, - mock=mock_find_valid_configs, + product_type=TargetsToValidFieldSets, + subject_type=TargetsToValidFieldSetsRequest, + mock=mock_find_valid_field_sets, ), MockGet( product_type=AddressAndTestResult, - subject_type=WrappedTestConfiguration, + subject_type=WrappedTestFieldSet, mock=lambda wrapped_config: mock_coordinator_of_tests(wrapped_config), ), MockGet( product_type=TestDebugRequest, - subject_type=TestConfiguration, + subject_type=TestFieldSet, mock=lambda _: TestDebugRequest(self.make_ipr()), ), MockGet( - product_type=ConfigurationsWithSources, - subject_type=ConfigurationsWithSourcesRequest, - mock=lambda configs: ConfigurationsWithSources( - configs if include_sources else () + product_type=FieldSetsWithSources, + subject_type=FieldSetsWithSourcesRequest, + mock=lambda field_sets: FieldSetsWithSources( + field_sets if include_sources else () ), ), MockGet( @@ -195,7 +200,7 @@ def mock_coordinator_of_tests( def test_empty_target_noops(self) -> None: exit_code, stdout = self.run_test_rule( - config=SuccessfulConfiguration, + field_set=SuccessfulFieldSet, targets=[self.make_target_with_origin()], include_sources=False, ) @@ -204,7 +209,7 @@ def test_empty_target_noops(self) -> None: def test_invalid_target_noops(self) -> None: exit_code, stdout = self.run_test_rule( - config=SuccessfulConfiguration, + field_set=SuccessfulFieldSet, targets=[self.make_target_with_origin()], valid_targets=False, ) @@ -214,13 +219,13 @@ def test_invalid_target_noops(self) -> None: def test_single_target(self) -> None: address = Address.parse(":tests") exit_code, stdout = self.run_test_rule( - config=SuccessfulConfiguration, targets=[self.make_target_with_origin(address)] + field_set=SuccessfulFieldSet, targets=[self.make_target_with_origin(address)] ) assert exit_code == 0 assert stdout == dedent( f"""\ {address} stdout: - {SuccessfulConfiguration.stdout(address)} + {SuccessfulFieldSet.stdout(address)} {address} ..... SUCCESS """ @@ -231,7 +236,7 @@ def test_multiple_targets(self) -> None: bad_address = Address.parse(":bad") exit_code, stdout = self.run_test_rule( - config=ConditionallySucceedsConfiguration, + field_set=ConditionallySucceedsFieldSet, targets=[ self.make_target_with_origin(good_address), self.make_target_with_origin(bad_address), @@ -241,9 +246,9 @@ def test_multiple_targets(self) -> None: assert stdout == dedent( f"""\ {good_address} stdout: - {ConditionallySucceedsConfiguration.stdout(good_address)} + {ConditionallySucceedsFieldSet.stdout(good_address)} {bad_address} stderr: - {ConditionallySucceedsConfiguration.stderr(bad_address)} + {ConditionallySucceedsFieldSet.stderr(bad_address)} {good_address} ..... SUCCESS {bad_address} ..... FAILURE @@ -252,6 +257,6 @@ def test_multiple_targets(self) -> None: def test_debug_target(self) -> None: exit_code, stdout = self.run_test_rule( - config=SuccessfulConfiguration, targets=[self.make_target_with_origin()], debug=True, + field_set=SuccessfulFieldSet, targets=[self.make_target_with_origin()], debug=True, ) assert exit_code == 0 diff --git a/src/python/pants/core/util_rules/filter_empty_sources.py b/src/python/pants/core/util_rules/filter_empty_sources.py index b69d814ada7..3e23b370d79 100644 --- a/src/python/pants/core/util_rules/filter_empty_sources.py +++ b/src/python/pants/core/util_rules/filter_empty_sources.py @@ -13,37 +13,37 @@ from pants.engine.target import Target -# This protocol allows us to work with any arbitrary Configuration. See +# This protocol allows us to work with any arbitrary FieldSet. See # https://mypy.readthedocs.io/en/stable/protocols.html. -class ConfigurationWithSources(Protocol): +class FieldSetWithSources(Protocol): @property def sources(self) -> SourcesField: ... -C = TypeVar("C", bound=ConfigurationWithSources) +_FS = TypeVar("_FS", bound=FieldSetWithSources) -class ConfigurationsWithSources(Collection[C]): - """Configurations which have non-empty source fields.""" +class FieldSetsWithSources(Collection[_FS]): + """Field sets which have non-empty source fields.""" -class ConfigurationsWithSourcesRequest(Collection[C]): - """Request to filter out all configs with empty source fields. +class FieldSetsWithSourcesRequest(Collection[_FS]): + """Request to filter out all field sets with empty source fields. - This works with any Configurations, so long as they have a `sources` field defined. + This works with any FieldSet, so long as it has a `sources` field defined. """ @rule -async def determine_configurations_with_sources( - request: ConfigurationsWithSourcesRequest, -) -> ConfigurationsWithSources: +async def determine_field_sets_with_sources( + request: FieldSetsWithSourcesRequest, +) -> FieldSetsWithSources: all_sources = await MultiGet( - Get[HydratedSources](HydrateSourcesRequest(config.sources)) for config in request + Get[HydratedSources](HydrateSourcesRequest(field_set.sources)) for field_set in request ) - return ConfigurationsWithSources( - config for config, sources in zip(request, all_sources) if sources.snapshot.files + return FieldSetsWithSources( + field_set for field_set, sources in zip(request, all_sources) if sources.snapshot.files ) @@ -67,8 +67,8 @@ async def determine_targets_with_sources(request: TargetsWithSourcesRequest) -> def rules(): return [ - determine_configurations_with_sources, + determine_field_sets_with_sources, determine_targets_with_sources, - RootRule(ConfigurationsWithSourcesRequest), + RootRule(FieldSetsWithSourcesRequest), RootRule(TargetsWithSourcesRequest), ] diff --git a/src/python/pants/core/util_rules/filter_empty_sources_test.py b/src/python/pants/core/util_rules/filter_empty_sources_test.py index 760c54c634e..9c5faf60e78 100644 --- a/src/python/pants/core/util_rules/filter_empty_sources_test.py +++ b/src/python/pants/core/util_rules/filter_empty_sources_test.py @@ -4,14 +4,14 @@ from dataclasses import dataclass from pants.core.util_rules.filter_empty_sources import ( - ConfigurationsWithSources, - ConfigurationsWithSourcesRequest, + FieldSetsWithSources, + FieldSetsWithSourcesRequest, TargetsWithSources, TargetsWithSourcesRequest, ) from pants.core.util_rules.filter_empty_sources import rules as filter_empty_sources_rules from pants.engine.addresses import Address -from pants.engine.target import Configuration, Sources, Tags, Target +from pants.engine.target import FieldSet, Sources, Tags, Target from pants.testutil.test_base import TestBase @@ -20,29 +20,28 @@ class FilterEmptySourcesTest(TestBase): def rules(cls): return (*super().rules(), *filter_empty_sources_rules()) - def test_filter_configurations(self) -> None: + def test_filter_field_sets(self) -> None: @dataclass(frozen=True) - class MockConfiguration(Configuration): + class MockFieldSet(FieldSet): sources: Sources - # Another field to demo that we will preserve the whole Configuration data structure. + # Another field to demo that we will preserve the whole FieldSet data structure. tags: Tags self.create_file("f1.txt") valid_addr = Address.parse(":valid") - valid_config = MockConfiguration( + valid_field_set = MockFieldSet( valid_addr, Sources(["f1.txt"], address=valid_addr), Tags(None, address=valid_addr) ) empty_addr = Address.parse(":empty") - empty_config = MockConfiguration( + empty_field_set = MockFieldSet( empty_addr, Sources(None, address=empty_addr), Tags(None, address=empty_addr) ) result = self.request_single_product( - ConfigurationsWithSources, - ConfigurationsWithSourcesRequest([valid_config, empty_config]), + FieldSetsWithSources, FieldSetsWithSourcesRequest([valid_field_set, empty_field_set]), ) - assert tuple(result) == (valid_config,) + assert tuple(result) == (valid_field_set,) def test_filter_targets(self) -> None: class MockTarget(Target): diff --git a/src/python/pants/engine/target.py b/src/python/pants/engine/target.py index 2fa645ccad6..8a904a76f2e 100644 --- a/src/python/pants/engine/target.py +++ b/src/python/pants/engine/target.py @@ -583,12 +583,12 @@ def types(self) -> Tuple[Type[Target], ...]: # ----------------------------------------------------------------------------------------------- -# Configuration +# FieldSet # ----------------------------------------------------------------------------------------------- @dataclass(frozen=True) -class _AbstractConfiguration(ABC): +class _AbstractFieldSet(ABC): required_fields: ClassVar[Tuple[Type[Field], ...]] address: Address @@ -610,28 +610,26 @@ def valid_target_types( ) -def _get_config_fields_from_target( - configuration: Type[_AbstractConfiguration], target: Target +def _get_field_set_fields_from_target( + field_set: Type[_AbstractFieldSet], target: Target ) -> Dict[str, Field]: all_expected_fields: Dict[str, Type[Field]] = { dataclass_field.name: dataclass_field.type - for dataclass_field in dataclasses.fields(configuration) + for dataclass_field in dataclasses.fields(field_set) if isinstance(dataclass_field.type, type) and issubclass(dataclass_field.type, Field) # type: ignore[unreachable] } return { dataclass_field_name: ( - target[field_cls] - if field_cls in configuration.required_fields - else target.get(field_cls) + target[field_cls] if field_cls in field_set.required_fields else target.get(field_cls) ) for dataclass_field_name, field_cls in all_expected_fields.items() } -_C = TypeVar("_C", bound="Configuration") +_FS = TypeVar("_FS", bound="FieldSet") -class Configuration(_AbstractConfiguration, metaclass=ABCMeta): +class FieldSet(_AbstractFieldSet, metaclass=ABCMeta): """An ad hoc set of fields from a target which are used by rules. Subclasses should declare all the fields they consume as dataclass attributes. They should also @@ -644,73 +642,71 @@ class Configuration(_AbstractConfiguration, metaclass=ABCMeta): For example: @dataclass(frozen=True) - class FortranTestConfiguration(Configuration): + class FortranTestFieldSet(FieldSet): required_fields = (FortranSources,) sources: FortranSources fortran_version: FortranVersion - This configuration may then created from a `Target` through the `is_valid()` and `create()` + This field set may then created from a `Target` through the `is_valid()` and `create()` class methods: - configs = [ - FortranTestConfiguration.create(tgt) for tgt in targets - if FortranTestConfiguration.is_valid(tgt) + field_sets = [ + FortranTestFieldSet.create(tgt) for tgt in targets + if FortranTestFieldSet.is_valid(tgt) ] - Configurations are consumed like any normal dataclass: + FieldSets are consumed like any normal dataclass: - print(config.address) - print(config.sources) + print(field_set.address) + print(field_set.sources) """ @classmethod - def create(cls: Type[_C], tgt: Target) -> _C: + def create(cls: Type[_FS], tgt: Target) -> _FS: return cls( # type: ignore[call-arg] - address=tgt.address, **_get_config_fields_from_target(cls, tgt) + address=tgt.address, **_get_field_set_fields_from_target(cls, tgt) ) -_CWO = TypeVar("_CWO", bound="ConfigurationWithOrigin") +_FSWO = TypeVar("_FSWO", bound="FieldSetWithOrigin") @dataclass(frozen=True) -class ConfigurationWithOrigin(_AbstractConfiguration, metaclass=ABCMeta): +class FieldSetWithOrigin(_AbstractFieldSet, metaclass=ABCMeta): """An ad hoc set of fields from a target which are used by rules, along with the original spec used to find the original target. - See Configuration for documentation on how subclasses should use this base class. + See FieldSet for documentation on how subclasses should use this base class. """ origin: OriginSpec @classmethod - def create(cls: Type[_CWO], target_with_origin: TargetWithOrigin) -> _CWO: + def create(cls: Type[_FSWO], target_with_origin: TargetWithOrigin) -> _FSWO: tgt = target_with_origin.target return cls( # type: ignore[call-arg] address=tgt.address, origin=target_with_origin.origin, - **_get_config_fields_from_target(cls, tgt), + **_get_field_set_fields_from_target(cls, tgt), ) @frozen_after_init @dataclass(unsafe_hash=True) -class TargetsToValidConfigurations: - mapping: FrozenDict[TargetWithOrigin, Tuple[_AbstractConfiguration, ...]] +class TargetsToValidFieldSets: + mapping: FrozenDict[TargetWithOrigin, Tuple[_AbstractFieldSet, ...]] - def __init__( - self, mapping: Mapping[TargetWithOrigin, Iterable[_AbstractConfiguration]] - ) -> None: + def __init__(self, mapping: Mapping[TargetWithOrigin, Iterable[_AbstractFieldSet]]) -> None: self.mapping = FrozenDict( - {tgt_with_origin: tuple(configs) for tgt_with_origin, configs in mapping.items()} + {tgt_with_origin: tuple(field_sets) for tgt_with_origin, field_sets in mapping.items()} ) @memoized_property - def configurations(self) -> Tuple[_AbstractConfiguration, ...]: + def field_sets(self) -> Tuple[_AbstractFieldSet, ...]: return tuple( itertools.chain.from_iterable( - configs_per_target for configs_per_target in self.mapping.values() + field_sets_per_target for field_sets_per_target in self.mapping.values() ) ) @@ -725,67 +721,67 @@ def targets_with_origins(self) -> Tuple[TargetWithOrigin, ...]: @frozen_after_init @dataclass(unsafe_hash=True) -class TargetsToValidConfigurationsRequest: - configuration_superclass: Type[_AbstractConfiguration] +class TargetsToValidFieldSetsRequest: + field_set_superclass: Type[_AbstractFieldSet] goal_description: str error_if_no_valid_targets: bool - expect_single_config: bool + expect_single_field_set: bool # TODO: Add a `require_sources` field. To do this, figure out the dependency cycle with # `util_rules/filter_empty_sources.py`. def __init__( self, - configuration_superclass: Type[_AbstractConfiguration], + field_set_superclass: Type[_AbstractFieldSet], *, goal_description: str, error_if_no_valid_targets: bool, - expect_single_config: bool = False, + expect_single_field_set: bool = False, ) -> None: - self.configuration_superclass = configuration_superclass + self.field_set_superclass = field_set_superclass self.goal_description = goal_description self.error_if_no_valid_targets = error_if_no_valid_targets - self.expect_single_config = expect_single_config + self.expect_single_field_set = expect_single_field_set @rule -def find_valid_configurations( - request: TargetsToValidConfigurationsRequest, +def find_valid_field_sets( + request: TargetsToValidFieldSetsRequest, targets_with_origins: TargetsWithOrigins, union_membership: UnionMembership, registered_target_types: RegisteredTargetTypes, -) -> TargetsToValidConfigurations: - config_types: Iterable[ - Union[Type[Configuration], Type[ConfigurationWithOrigin]] - ] = union_membership.union_rules[request.configuration_superclass] - targets_to_valid_configs = {} +) -> TargetsToValidFieldSets: + field_set_types: Iterable[ + Union[Type[FieldSet], Type[FieldSetWithOrigin]] + ] = union_membership.union_rules[request.field_set_superclass] + targets_to_valid_field_sets = {} for tgt_with_origin in targets_with_origins: - valid_configs = [ + valid_field_sets = [ ( - config_type.create(tgt_with_origin) - if issubclass(config_type, ConfigurationWithOrigin) - else config_type.create(tgt_with_origin.target) + field_set_type.create(tgt_with_origin) + if issubclass(field_set_type, FieldSetWithOrigin) + else field_set_type.create(tgt_with_origin.target) ) - for config_type in config_types - if config_type.is_valid(tgt_with_origin.target) + for field_set_type in field_set_types + if field_set_type.is_valid(tgt_with_origin.target) ] - if valid_configs: - targets_to_valid_configs[tgt_with_origin] = valid_configs - if request.error_if_no_valid_targets and not targets_to_valid_configs: - raise NoValidTargetsException.create_from_configs( + if valid_field_sets: + targets_to_valid_field_sets[tgt_with_origin] = valid_field_sets + if request.error_if_no_valid_targets and not targets_to_valid_field_sets: + raise NoValidTargetsException.create_from_field_sets( targets_with_origins, - config_types=config_types, + field_set_types=field_set_types, goal_description=request.goal_description, union_membership=union_membership, registered_target_types=registered_target_types, ) - result = TargetsToValidConfigurations(targets_to_valid_configs) - if not request.expect_single_config: + result = TargetsToValidFieldSets(targets_to_valid_field_sets) + if not request.expect_single_field_set: return result if len(result.targets) > 1: raise TooManyTargetsException(result.targets, goal_description=request.goal_description) - if len(result.configurations) > 1: + if len(result.field_sets) > 1: raise AmbiguousImplementationsException( - result.targets[0], result.configurations, goal_description=request.goal_description + result.targets[0], result.field_sets, goal_description=request.goal_description ) return result @@ -863,19 +859,19 @@ def __init__( ) @classmethod - def create_from_configs( + def create_from_field_sets( cls, targets_with_origins: TargetsWithOrigins, *, - config_types: Iterable[Type[_AbstractConfiguration]], + field_set_types: Iterable[Type[_AbstractFieldSet]], goal_description: str, union_membership: UnionMembership, registered_target_types: RegisteredTargetTypes, ) -> "NoValidTargetsException": valid_target_types = { target_type - for config_type in config_types - for target_type in config_type.valid_target_types( + for field_set_type in field_set_types + for target_type in field_set_type.valid_target_types( registered_target_types.types, union_membership=union_membership ) } @@ -900,25 +896,21 @@ def __init__(self, targets: Iterable[Target], *, goal_description: str) -> None: # NB: This has a tight coupling to goals. Feel free to change this if necessary. class AmbiguousImplementationsException(Exception): - """Exception for when a single target has multiple valid Configurations, but the goal only - expects there to be one Configuration.""" + """Exception for when a single target has multiple valid FieldSets, but the goal only expects + there to be one FieldSet.""" def __init__( - self, - target: Target, - configurations: Iterable[_AbstractConfiguration], - *, - goal_description: str, + self, target: Target, field_sets: Iterable[_AbstractFieldSet], *, goal_description: str, ) -> None: # TODO: improve this error message. A better error message would explain to users how they # can resolve the issue. - possible_config_types = sorted(config.__class__.__name__ for config in configurations) + possible_field_sets_types = sorted(field_set.__class__.__name__ for field_set in field_sets) bulleted_list_sep = "\n * " super().__init__( f"Multiple of the registered implementations for {goal_description} work for " f"{target.address} (target type {repr(target.alias)}). It is ambiguous which " "implementation to use.\n\nPossible implementations:" - f"{bulleted_list_sep}{bulleted_list_sep.join(possible_config_types)}" + f"{bulleted_list_sep}{bulleted_list_sep.join(possible_field_sets_types)}" ) @@ -1662,8 +1654,8 @@ def request(self): def rules(): return [ - find_valid_configurations, + find_valid_field_sets, hydrate_sources, - RootRule(TargetsToValidConfigurationsRequest), + RootRule(TargetsToValidFieldSetsRequest), RootRule(HydrateSourcesRequest), ] diff --git a/src/python/pants/engine/target_test.py b/src/python/pants/engine/target_test.py index 6ae9e4385a5..ccd0f71436f 100644 --- a/src/python/pants/engine/target_test.py +++ b/src/python/pants/engine/target_test.py @@ -20,10 +20,10 @@ AmbiguousImplementationsException, AsyncField, BoolField, - Configuration, - ConfigurationWithOrigin, DictStringToStringField, DictStringToStringSequenceField, + FieldSet, + FieldSetWithOrigin, GeneratedSources, GenerateSourcesRequest, HydratedSources, @@ -41,8 +41,8 @@ StringOrStringSequenceField, StringSequenceField, Target, - TargetsToValidConfigurations, - TargetsToValidConfigurationsRequest, + TargetsToValidFieldSets, + TargetsToValidFieldSetsRequest, TargetsWithOrigins, TargetWithOrigin, TooManyTargetsException, @@ -407,11 +407,11 @@ class RequiredTarget(Target): # ----------------------------------------------------------------------------------------------- -# Test Configuration +# Test FieldSet # ----------------------------------------------------------------------------------------------- -def test_configuration() -> None: +def test_field_set() -> None: class UnrelatedField(StringField): alias = "unrelated_field" default = "default" @@ -426,14 +426,14 @@ class NoFieldsTarget(Target): core_fields = () @dataclass(frozen=True) - class FortranConfiguration(Configuration): + class FortranFieldSet(FieldSet): required_fields = (FortranSources,) sources: FortranSources unrelated_field: UnrelatedField @dataclass(frozen=True) - class UnrelatedFieldConfiguration(ConfigurationWithOrigin): + class UnrelatedFieldSet(FieldSetWithOrigin): required_fields = () unrelated_field: UnrelatedField @@ -445,38 +445,32 @@ class UnrelatedFieldConfiguration(ConfigurationWithOrigin): no_fields_addr = Address.parse(":no_fields") no_fields_tgt = NoFieldsTarget({}, address=no_fields_addr) - assert FortranConfiguration.is_valid(fortran_tgt) is True - assert FortranConfiguration.is_valid(unrelated_tgt) is False - assert FortranConfiguration.is_valid(no_fields_tgt) is False + assert FortranFieldSet.is_valid(fortran_tgt) is True + assert FortranFieldSet.is_valid(unrelated_tgt) is False + assert FortranFieldSet.is_valid(no_fields_tgt) is False # When no fields are required, every target is valid. for tgt in [fortran_tgt, unrelated_tgt, no_fields_tgt]: - assert UnrelatedFieldConfiguration.is_valid(tgt) is True + assert UnrelatedFieldSet.is_valid(tgt) is True - valid_fortran_config = FortranConfiguration.create(fortran_tgt) - assert valid_fortran_config.address == fortran_addr - assert valid_fortran_config.unrelated_field.value == UnrelatedField.default + valid_fortran_field_set = FortranFieldSet.create(fortran_tgt) + assert valid_fortran_field_set.address == fortran_addr + assert valid_fortran_field_set.unrelated_field.value == UnrelatedField.default with pytest.raises(KeyError): - FortranConfiguration.create(unrelated_tgt) + FortranFieldSet.create(unrelated_tgt) origin = FilesystemLiteralSpec("f.txt") + assert UnrelatedFieldSet.create(TargetWithOrigin(fortran_tgt, origin)).origin == origin assert ( - UnrelatedFieldConfiguration.create(TargetWithOrigin(fortran_tgt, origin)).origin == origin - ) - assert ( - UnrelatedFieldConfiguration.create( - TargetWithOrigin(unrelated_tgt, origin) - ).unrelated_field.value + UnrelatedFieldSet.create(TargetWithOrigin(unrelated_tgt, origin)).unrelated_field.value == "configured" ) assert ( - UnrelatedFieldConfiguration.create( - TargetWithOrigin(no_fields_tgt, origin) - ).unrelated_field.value + UnrelatedFieldSet.create(TargetWithOrigin(no_fields_tgt, origin)).unrelated_field.value == UnrelatedField.default ) -class TestFindValidConfigurations(TestBase): +class TestFindValidFieldSets(TestBase): class InvalidTarget(Target): alias = "invalid_target" core_fields = () @@ -486,26 +480,26 @@ def target_types(cls): return [FortranTarget, cls.InvalidTarget] @union - class ConfigSuperclass(Configuration): + class FieldSetSuperclass(FieldSet): pass @dataclass(frozen=True) - class ConfigSubclass1(ConfigSuperclass): + class FieldSetSubclass1(FieldSetSuperclass): required_fields = (FortranSources,) sources: FortranSources @dataclass(frozen=True) - class ConfigSubclass2(ConfigSuperclass): + class FieldSetSubclass2(FieldSetSuperclass): required_fields = (FortranSources,) sources: FortranSources @union - class ConfigSuperclassWithOrigin(ConfigurationWithOrigin): + class FieldSetSuperclassWithOrigin(FieldSetWithOrigin): pass - class ConfigSubclassWithOrigin(ConfigSuperclassWithOrigin): + class FieldSetSubclassWithOrigin(FieldSetSuperclassWithOrigin): required_fields = (FortranSources,) sources: FortranSources @@ -515,55 +509,54 @@ def rules(cls): return ( *super().rules(), RootRule(TargetsWithOrigins), - UnionRule(cls.ConfigSuperclass, cls.ConfigSubclass1), - UnionRule(cls.ConfigSuperclass, cls.ConfigSubclass2), - UnionRule(cls.ConfigSuperclassWithOrigin, cls.ConfigSubclassWithOrigin), + UnionRule(cls.FieldSetSuperclass, cls.FieldSetSubclass1), + UnionRule(cls.FieldSetSuperclass, cls.FieldSetSubclass2), + UnionRule(cls.FieldSetSuperclassWithOrigin, cls.FieldSetSubclassWithOrigin), ) - def test_find_valid_config_types(self) -> None: + def test_find_valid_field_sets(self) -> None: origin = FilesystemLiteralSpec("f.txt") valid_tgt = FortranTarget({}, address=Address.parse(":valid")) valid_tgt_with_origin = TargetWithOrigin(valid_tgt, origin) invalid_tgt = self.InvalidTarget({}, address=Address.parse(":invalid")) invalid_tgt_with_origin = TargetWithOrigin(invalid_tgt, origin) - def find_valid_configs( + def find_valid_field_sets( superclass: Type, targets_with_origins: Iterable[TargetWithOrigin], *, error_if_no_valid_targets: bool = False, expect_single_config: bool = False, - ) -> TargetsToValidConfigurations: - request = TargetsToValidConfigurationsRequest( + ) -> TargetsToValidFieldSets: + request = TargetsToValidFieldSetsRequest( superclass, goal_description="fake", error_if_no_valid_targets=error_if_no_valid_targets, - expect_single_config=expect_single_config, + expect_single_field_set=expect_single_config, ) return self.request_single_product( - TargetsToValidConfigurations, - Params(request, TargetsWithOrigins(targets_with_origins),), + TargetsToValidFieldSets, Params(request, TargetsWithOrigins(targets_with_origins),), ) - valid = find_valid_configs( - self.ConfigSuperclass, [valid_tgt_with_origin, invalid_tgt_with_origin] + valid = find_valid_field_sets( + self.FieldSetSuperclass, [valid_tgt_with_origin, invalid_tgt_with_origin] ) assert valid.targets == (valid_tgt,) assert valid.targets_with_origins == (valid_tgt_with_origin,) - assert valid.configurations == ( - self.ConfigSubclass1.create(valid_tgt), - self.ConfigSubclass2.create(valid_tgt), + assert valid.field_sets == ( + self.FieldSetSubclass1.create(valid_tgt), + self.FieldSetSubclass2.create(valid_tgt), ) with pytest.raises(ExecutionError) as exc: - find_valid_configs( - self.ConfigSuperclass, [valid_tgt_with_origin], expect_single_config=True + find_valid_field_sets( + self.FieldSetSuperclass, [valid_tgt_with_origin], expect_single_config=True ) assert AmbiguousImplementationsException.__name__ in str(exc.value) with pytest.raises(ExecutionError) as exc: - find_valid_configs( - self.ConfigSuperclass, + find_valid_field_sets( + self.FieldSetSuperclass, [ valid_tgt_with_origin, TargetWithOrigin(FortranTarget({}, address=Address.parse(":valid2")), origin), @@ -572,24 +565,24 @@ def find_valid_configs( ) assert TooManyTargetsException.__name__ in str(exc.value) - no_valid_targets = find_valid_configs(self.ConfigSuperclass, [invalid_tgt_with_origin]) + no_valid_targets = find_valid_field_sets(self.FieldSetSuperclass, [invalid_tgt_with_origin]) assert no_valid_targets.targets == () assert no_valid_targets.targets_with_origins == () - assert no_valid_targets.configurations == () + assert no_valid_targets.field_sets == () with pytest.raises(ExecutionError) as exc: - find_valid_configs( - self.ConfigSuperclass, [invalid_tgt_with_origin], error_if_no_valid_targets=True + find_valid_field_sets( + self.FieldSetSuperclass, [invalid_tgt_with_origin], error_if_no_valid_targets=True ) assert NoValidTargetsException.__name__ in str(exc.value) - valid_with_origin = find_valid_configs( - self.ConfigSuperclassWithOrigin, [valid_tgt_with_origin, invalid_tgt_with_origin] + valid_with_origin = find_valid_field_sets( + self.FieldSetSuperclassWithOrigin, [valid_tgt_with_origin, invalid_tgt_with_origin] ) assert valid_with_origin.targets == (valid_tgt,) assert valid_with_origin.targets_with_origins == (valid_tgt_with_origin,) - assert valid_with_origin.configurations == ( - self.ConfigSubclassWithOrigin.create(valid_tgt_with_origin), + assert valid_with_origin.field_sets == ( + self.FieldSetSubclassWithOrigin.create(valid_tgt_with_origin), )