def test_explicitly_provided_dependencies_disambiguated() -> None: def get_disambiguated( ambiguous: List[Address], *, ignores: Optional[List[Address]] = None, includes: Optional[List[Address]] = None, owners_must_be_ancestors: bool = False, ) -> Optional[Address]: epd = ExplicitlyProvidedDependencies( address=Address("dir", target_name="input_tgt"), includes=FrozenOrderedSet(includes or []), ignores=FrozenOrderedSet(ignores or []), ) return epd.disambiguated( tuple(ambiguous), owners_must_be_ancestors=owners_must_be_ancestors) # A mix of normal and generated addresses. addr_a = Address("dir", target_name="a", generated_name="gen") addr_b = Address("dir", target_name="b", generated_name="gen") addr_c = Address("dir", target_name="c") all_addr = [addr_a, addr_b, addr_c] # If 1 target remains, it's disambiguated. Note that ignores can be normal or generated targets. assert get_disambiguated(all_addr, ignores=[addr_b, addr_c]) == addr_a assert (get_disambiguated( all_addr, ignores=[addr_b.maybe_convert_to_target_generator(), addr_c]) == addr_a) assert get_disambiguated(all_addr, ignores=[addr_a]) is None assert get_disambiguated( all_addr, ignores=[addr_a.maybe_convert_to_target_generator()]) is None assert get_disambiguated(all_addr, ignores=all_addr) is None assert get_disambiguated([]) is None # If any includes would disambiguate the ambiguous target, we don't consider disambiguating # via excludes as the user has already explicitly disambiguated the module. assert get_disambiguated( all_addr, ignores=[addr_a, addr_b], includes=[addr_a]) is None assert (get_disambiguated( ambiguous=all_addr, ignores=[addr_a, addr_b], includes=[addr_a.maybe_convert_to_target_generator()], ) is None) # You can also disambiguate via `owners_must_be_ancestors`. another_dir = Address("another_dir") assert get_disambiguated([addr_a, another_dir], owners_must_be_ancestors=True) == addr_a assert get_disambiguated([addr_a, another_dir], owners_must_be_ancestors=False) is None assert (get_disambiguated([addr_a, addr_b, another_dir], ignores=[addr_b], owners_must_be_ancestors=True) == addr_a)
async def find_build_file(address: Address) -> BuildFileAddress: address_family = await Get(AddressFamily, AddressFamilyDir(address.spec_path)) owning_address = address.maybe_convert_to_target_generator() if address_family.get_target_adaptor(owning_address) is None: raise ResolveError.did_you_mean( bad_name=owning_address.target_name, known_names=address_family.target_names, namespace=address_family.namespace, ) bfa = next(build_file_address for build_file_address in address_family.build_file_addresses if build_file_address.address == owning_address) return BuildFileAddress( address, bfa.rel_path) if address.is_generated_target else bfa
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])
def test_explicitly_provided_dependencies_maybe_warn_of_ambiguous_dependency_inference( caplog, ) -> None: def maybe_warn( ambiguous: List[Address], *, ignores: Optional[List[Address]] = None, includes: Optional[List[Address]] = None, owners_must_be_ancestors: bool = False, ) -> None: caplog.clear() epd = ExplicitlyProvidedDependencies( Address("dir", target_name="input_tgt"), includes=FrozenOrderedSet(includes or []), ignores=FrozenOrderedSet(ignores or []), ) epd.maybe_warn_of_ambiguous_dependency_inference( tuple(ambiguous), Address("some_dir"), import_reference="file", context="foo", owners_must_be_ancestors=owners_must_be_ancestors, ) maybe_warn([]) assert not caplog.records # A mix of normal and generated addresses. addr_a = Address("dir", target_name="a", generated_name="gen") addr_b = Address("dir", target_name="b", generated_name="gen") addr_c = Address("dir", target_name="c") all_addr = [addr_a, addr_b, addr_c] maybe_warn(all_addr) assert len(caplog.records) == 1 assert f"['{addr_a}', '{addr_b}', '{addr_c}']" in caplog.text # Ignored addresses do not show up in the list of ambiguous owners, including for ignores of # both file and BUILD targets. maybe_warn(all_addr, ignores=[addr_b]) assert len(caplog.records) == 1 assert f"['{addr_a}', '{addr_c}']" in caplog.text maybe_warn(all_addr, ignores=[addr_b.maybe_convert_to_target_generator()]) assert len(caplog.records) == 1 assert f"['{addr_a}', '{addr_c}']" in caplog.text # Disambiguating via ignores turns off the warning, including for ignores of both normal and # generated targets. maybe_warn(all_addr, ignores=[addr_a, addr_b]) assert not caplog.records maybe_warn( all_addr, ignores=[ addr_a.maybe_convert_to_target_generator(), addr_b.maybe_convert_to_target_generator(), ], ) assert not caplog.records # Including a target turns off the warning, including for includes of both normal and generated # targets. maybe_warn(all_addr, includes=[addr_a]) assert not caplog.records maybe_warn(all_addr, includes=[addr_a.maybe_convert_to_target_generator()]) assert not caplog.records # You can also disambiguate via `owners_must_be_ancestors`. another_dir = Address("another_dir") maybe_warn([addr_a, another_dir], owners_must_be_ancestors=True) assert not caplog.records maybe_warn([addr_a, another_dir], owners_must_be_ancestors=False) assert len(caplog.records) == 1 assert f"['{another_dir}', '{addr_a}']" in caplog.text maybe_warn([addr_a, addr_b, another_dir], ignores=[addr_b], owners_must_be_ancestors=True) assert not caplog.records