async def resolve_targets( targets: UnexpandedTargets, target_types_to_generate_requests: TargetTypesToGenerateTargetsRequests, ) -> Targets: # Replace all generating targets with what they generate. Otherwise, keep them. If a target # generator does not generate any targets, keep the target generator. # TODO: This method does not preserve the order of inputs. expanded_targets: OrderedSet[Target] = OrderedSet() generator_targets = [] parametrizations_gets = [] for tgt in targets: if (target_types_to_generate_requests.is_generator(tgt) and not tgt.address.is_generated_target): generator_targets.append(tgt) parametrizations_gets.append( Get( _TargetParametrizations, _TargetParametrizationsRequest( tgt.address.maybe_convert_to_target_generator(), description_of_origin="TODO(#14468)", ), )) else: expanded_targets.add(tgt) all_generated_targets = await MultiGet(parametrizations_gets) expanded_targets.update( tgt for generator, parametrizations in zip(generator_targets, all_generated_targets) for tgt in parametrizations.generated_or_generator(generator.address)) return Targets(expanded_targets)
def target_types_to_generate_targets_requests( union_membership: UnionMembership, ) -> TargetTypesToGenerateTargetsRequests: return TargetTypesToGenerateTargetsRequests({ request_cls.generate_from: request_cls # type: ignore[misc] for request_cls in union_membership.get(GenerateTargetsRequest) })
async def resolve_target( request: WrappedTargetRequest, target_types_to_generate_requests: TargetTypesToGenerateTargetsRequests, ) -> WrappedTarget: address = request.address base_address = address.maybe_convert_to_target_generator() parametrizations = await Get( _TargetParametrizations, _TargetParametrizationsRequest( base_address, description_of_origin=request.description_of_origin), ) if address.is_generated_target: # TODO: This is an accommodation to allow using file/generator Addresses for # non-generator atom targets. See https://github.com/pantsbuild/pants/issues/14419. original_target = parametrizations.get(base_address) if original_target and not target_types_to_generate_requests.is_generator( original_target): return WrappedTarget(original_target) target = parametrizations.get(address) if target is None: raise ValueError( f"The address `{address}` was not generated by the target `{base_address}`, which " "only generated these addresses:\n\n" f"{bullet_list(str(t.address) for t in parametrizations.all)}\n\n" "Did you mean to use one of those addresses?") return WrappedTarget(target)
async def resolve_targets( targets: UnexpandedTargets, target_types_to_generate_requests: TargetTypesToGenerateTargetsRequests, ) -> Targets: # Replace all generating targets with what it generates. Otherwise, keep it. If a target # generator does not generate any targets, keep the target generator. expanded_targets: OrderedSet[Target] = OrderedSet() generator_targets = [] generate_gets = [] for tgt in targets: if (target_types_to_generate_requests.is_generator(tgt) and not tgt.address.is_generated_target): generator_targets.append(tgt) generate_request = target_types_to_generate_requests[type(tgt)] generate_gets.append( Get(GeneratedTargets, GenerateTargetsRequest, generate_request(tgt))) else: expanded_targets.add(tgt) all_generated_targets = await MultiGet(generate_gets) expanded_targets.update(tgt for generator, generated_targets in zip( generator_targets, all_generated_targets) for tgt in ( generated_targets.values() if generated_targets else {generator})) return Targets(expanded_targets)
async def resolve_target( address: Address, registered_target_types: RegisteredTargetTypes, union_membership: UnionMembership, target_types_to_generate_requests: TargetTypesToGenerateTargetsRequests, ) -> WrappedTarget: if not address.is_generated_target: target_adaptor = await Get(TargetAdaptor, Address, address) target_type = registered_target_types.aliases_to_types.get( target_adaptor.type_alias, None) if target_type is None: raise UnrecognizedTargetTypeException(target_adaptor.type_alias, registered_target_types, address) if (target_type.deprecated_alias is not None and target_type.deprecated_alias == target_adaptor.type_alias and not address.is_generated_target): await Get(_WarnDeprecatedTarget, _WarnDeprecatedTargetRequest(target_type)) target = target_type(target_adaptor.kwargs, address, union_membership) return WrappedTarget(target) wrapped_generator_tgt = await Get( WrappedTarget, Address, address.maybe_convert_to_target_generator()) generator_tgt = wrapped_generator_tgt.target if not target_types_to_generate_requests.is_generator(generator_tgt): # TODO: Error in this case. You should not use a generator address (or file address) if # the generator does not actually generate. return wrapped_generator_tgt generate_request = target_types_to_generate_requests[type(generator_tgt)] generated = await Get(GeneratedTargets, GenerateTargetsRequest, generate_request(generator_tgt)) if address not in generated: raise ValueError( f"The address `{address}` is not generated by the `{generator_tgt.alias}` target " f"`{generator_tgt.address}`, which only generates these addresses:\n\n" f"{bullet_list(addr.spec for addr in generated)}\n\n" "Did you mean to use one of those addresses?") return WrappedTarget(generated[address])
async def resolve_target_parametrizations( request: _TargetParametrizationsRequest, registered_target_types: RegisteredTargetTypes, union_membership: UnionMembership, target_types_to_generate_requests: TargetTypesToGenerateTargetsRequests, unmatched_build_file_globs: UnmatchedBuildFileGlobs, ) -> _TargetParametrizations: address = request.address target_adaptor = await Get(TargetAdaptor, Address, address) target_type = registered_target_types.aliases_to_types.get( target_adaptor.type_alias, None) if target_type is None: raise UnrecognizedTargetTypeException(target_adaptor.type_alias, registered_target_types, address) if (target_type.deprecated_alias is not None and target_type.deprecated_alias == target_adaptor.type_alias and not address.is_generated_target): warn_deprecated_target_type(target_type) target = None parametrizations: list[_TargetParametrization] = [] generate_request: type[GenerateTargetsRequest] | None = None if issubclass(target_type, TargetGenerator): generate_request = target_types_to_generate_requests.request_for( target_type) if generate_request: # Split out the `propagated_fields` before construction. generator_fields = dict(target_adaptor.kwargs) template_fields = {} if issubclass(target_type, TargetGenerator): copied_fields = ( *target_type.copied_fields, *target_type._find_plugin_fields(union_membership), ) for field_type in copied_fields: field_value = generator_fields.get(field_type.alias, None) if field_value is not None: template_fields[field_type.alias] = field_value for field_type in target_type.moved_fields: field_value = generator_fields.pop(field_type.alias, None) if field_value is not None: template_fields[field_type.alias] = field_value generator_fields_parametrized = { name for name, field in generator_fields.items() if isinstance(field, Parametrize) } if generator_fields_parametrized: noun = pluralize(len(generator_fields_parametrized), "field", include_count=False) raise ValueError( f"Only fields which will be moved to generated targets may be parametrized, " f"so target generator {address} (with type {target_type.alias}) cannot " f"parametrize the {generator_fields_parametrized} {noun}.") base_generator = target_type( generator_fields, address, name_explicitly_set=target_adaptor.name_explicitly_set, union_membership=union_membership, ) overrides = {} if base_generator.has_field(OverridesField): overrides_field = base_generator[OverridesField] overrides_flattened = overrides_field.flatten() if issubclass(target_type, TargetFilesGenerator): override_globs = OverridesField.to_path_globs( address, overrides_flattened, unmatched_build_file_globs) override_paths = await MultiGet( Get(Paths, PathGlobs, path_globs) for path_globs in override_globs) overrides = OverridesField.flatten_paths( address, zip(override_paths, override_globs, overrides_flattened.values()), ) else: overrides = overrides_field.flatten() generators = [( target_type( generator_fields, address, name_explicitly_set=target_adaptor.name is not None, union_membership=union_membership, ), template, ) for address, template in Parametrize.expand(address, template_fields) ] all_generated = await MultiGet( Get( GeneratedTargets, GenerateTargetsRequest, generate_request( generator, template_address=generator.address, template=template, overrides={ name: dict( Parametrize.expand(generator.address, override)) for name, override in overrides.items() }, ), ) for generator, template in generators) parametrizations.extend( _TargetParametrization(generator, generated_batch) for generated_batch, (generator, _) in zip(all_generated, generators)) else: first, *rest = Parametrize.expand(address, target_adaptor.kwargs) if rest: # The target was parametrized, and so the original Target does not exist. generated = FrozenDict(( parameterized_address, target_type( parameterized_fields, parameterized_address, name_explicitly_set=target_adaptor.name_explicitly_set, union_membership=union_membership, ), ) for parameterized_address, parameterized_fields in (first, *rest)) parametrizations.append(_TargetParametrization(None, generated)) else: # The target was not parametrized. target = target_type( target_adaptor.kwargs, address, name_explicitly_set=target_adaptor.name_explicitly_set, union_membership=union_membership, ) parametrizations.append( _TargetParametrization(target, FrozenDict())) # TODO: Move to Target constructor. for field_type in target.field_types if target else (): if (field_type.deprecated_alias is not None and field_type.deprecated_alias in target_adaptor.kwargs): warn_deprecated_field_type(field_type) return _TargetParametrizations(parametrizations)
async def resolve_dependencies( request: DependenciesRequest, target_types_to_generate_requests: TargetTypesToGenerateTargetsRequests, union_membership: UnionMembership, subproject_roots: SubprojectRoots, ) -> Addresses: wrapped_tgt, explicitly_provided = await MultiGet( Get( WrappedTarget, WrappedTargetRequest(request.field.address, description_of_origin="<infallible>"), ), Get(ExplicitlyProvidedDependencies, DependenciesRequest, request), ) tgt = wrapped_tgt.target # Inject any dependencies (based on `Dependencies` field rather than `SourcesField`). inject_request_types = union_membership.get(InjectDependenciesRequest) injected = await MultiGet( Get(InjectedDependencies, InjectDependenciesRequest, inject_request_type(request.field)) for inject_request_type in inject_request_types if isinstance(request.field, inject_request_type.inject_for)) # Infer any dependencies (based on `SourcesField` field). inference_request_types = union_membership.get(InferDependenciesRequest) inferred: tuple[InferredDependencies, ...] = () if inference_request_types: sources_field = tgt.get(SourcesField) relevant_inference_request_types = [ inference_request_type for inference_request_type in inference_request_types if isinstance(sources_field, inference_request_type.infer_from) ] inferred = await MultiGet( Get( InferredDependencies, InferDependenciesRequest, inference_request_type(sources_field), ) for inference_request_type in relevant_inference_request_types) # If it's a target generator, inject dependencies on all of its generated targets. generated_addresses: tuple[Address, ...] = () if target_types_to_generate_requests.is_generator( tgt) and not tgt.address.is_generated_target: parametrizations = await Get( _TargetParametrizations, _TargetParametrizationsRequest( tgt.address.maybe_convert_to_target_generator(), description_of_origin= (f"the target generator {tgt.address.maybe_convert_to_target_generator()}" ), ), ) generated_addresses = tuple( parametrizations.generated_for(tgt.address).keys()) # If the target is parametrized, see whether any explicitly provided dependencies are also # parametrized, but with partial/no parameters. If so, fill them in. explicitly_provided_includes: Iterable[ Address] = explicitly_provided.includes if request.field.address.is_parametrized and explicitly_provided_includes: explicit_dependency_parametrizations = await MultiGet( Get( _TargetParametrizations, _TargetParametrizationsRequest( address.maybe_convert_to_target_generator(), description_of_origin= (f"the `{request.field.alias}` field of the target {tgt.address}" ), ), ) for address in explicitly_provided_includes) explicitly_provided_includes = [ parametrizations.get_subset(address, tgt).address for address, parametrizations in zip( explicitly_provided_includes, explicit_dependency_parametrizations) ] # If the target has `SpecialCasedDependencies`, such as the `archive` target having # `files` and `packages` fields, then we possibly include those too. We don't want to always # include those dependencies because they should often be excluded from the result due to # being handled elsewhere in the calling code. special_cased: tuple[Address, ...] = () if request.include_special_cased_deps: # Unlike normal, we don't use `tgt.get()` because there may be >1 subclass of # SpecialCasedDependencies. special_cased_fields = tuple( field for field in tgt.field_values.values() if isinstance(field, SpecialCasedDependencies)) # We can't use the normal `Get(Addresses, UnparsedAddressInputs)` due to a graph cycle. special_cased = await MultiGet( Get( Address, AddressInput, AddressInput.parse( addr, relative_to=tgt.address.spec_path, subproject_roots=subproject_roots, description_of_origin= (f"the `{special_cased_field.alias}` field from the target {tgt.address}" ), ), ) for special_cased_field in special_cased_fields for addr in special_cased_field.to_unparsed_address_inputs().values ) result = Addresses( sorted({ addr for addr in ( *generated_addresses, *explicitly_provided_includes, *itertools.chain.from_iterable(injected), *itertools.chain.from_iterable(inferred), *special_cased, ) if addr not in explicitly_provided.ignores })) # Validate dependencies. _ = await MultiGet( Get( ValidatedDependencies, ValidateDependenciesRequest, vd_request_type(vd_request_type.field_set_type.create(tgt), result), # type: ignore[misc] ) for vd_request_type in union_membership.get( ValidateDependenciesRequest) if vd_request_type.field_set_type.is_applicable(tgt) # type: ignore[misc] ) return result
async def resolve_dependencies( request: DependenciesRequest, target_types_to_generate_requests: TargetTypesToGenerateTargetsRequests, union_membership: UnionMembership, global_options: GlobalOptions, ) -> Addresses: wrapped_tgt, explicitly_provided = await MultiGet( Get(WrappedTarget, Address, request.field.address), Get(ExplicitlyProvidedDependencies, DependenciesRequest, request), ) tgt = wrapped_tgt.target # Inject any dependencies (based on `Dependencies` field rather than `Sources` field). inject_request_types = union_membership.get(InjectDependenciesRequest) injected = await MultiGet( Get(InjectedDependencies, InjectDependenciesRequest, inject_request_type(request.field)) for inject_request_type in inject_request_types if isinstance(request.field, inject_request_type.inject_for)) # Infer any dependencies (based on `Sources` field). inference_request_types = union_membership.get(InferDependenciesRequest) inferred: Tuple[InferredDependencies, ...] = () if inference_request_types: sources_field = tgt.get(Sources) relevant_inference_request_types = [ inference_request_type for inference_request_type in inference_request_types if isinstance(sources_field, inference_request_type.infer_from) ] inferred = await MultiGet( Get( InferredDependencies, InferDependenciesRequest, inference_request_type(sources_field), ) for inference_request_type in relevant_inference_request_types) # If it's a target generator, inject dependencies on all of its generated targets. generated_addresses: tuple[Address, ...] = () if target_types_to_generate_requests.is_generator( tgt) and not tgt.address.is_generated_target: generate_request = target_types_to_generate_requests[type(tgt)] generated_targets = await Get(GeneratedTargets, GenerateTargetsRequest, generate_request(tgt)) generated_addresses = tuple(generated_targets.keys()) # If the target has `SpecialCasedDependencies`, such as the `archive` target having # `files` and `packages` fields, then we possibly include those too. We don't want to always # include those dependencies because they should often be excluded from the result due to # being handled elsewhere in the calling code. special_cased: Tuple[Address, ...] = () if request.include_special_cased_deps: # Unlike normal, we don't use `tgt.get()` because there may be >1 subclass of # SpecialCasedDependencies. special_cased_fields = tuple( field for field in tgt.field_values.values() if isinstance(field, SpecialCasedDependencies)) # We can't use the normal `Get(Addresses, UnparsedAddressInputs)` due to a graph cycle. special_cased = await MultiGet( Get( Address, AddressInput, AddressInput.parse( addr, relative_to=tgt.address.spec_path, subproject_roots=global_options.options.subproject_roots, ), ) for special_cased_field in special_cased_fields for addr in special_cased_field.to_unparsed_address_inputs().values ) result = { addr for addr in ( *generated_addresses, *explicitly_provided.includes, *itertools.chain.from_iterable(injected), *itertools.chain.from_iterable(inferred), *special_cased, ) if addr not in explicitly_provided.ignores } return Addresses(sorted(result))