def test_map_first_party_modules_to_addresses(rule_runner: RuleRunner) -> None: rule_runner.set_options( ["--source-root-patterns=['src/python', 'tests/python', 'build-support']"] ) # Two modules belonging to the same target. We should generate subtargets for each file. rule_runner.create_files("src/python/project/util", ["dirutil.py", "tarutil.py"]) rule_runner.add_to_build_file("src/python/project/util", "python_library()") # A module with two owners, meaning that neither should be resolved. rule_runner.create_file("src/python/two_owners.py") rule_runner.add_to_build_file("src/python", "python_library()") rule_runner.create_file("build-support/two_owners.py") rule_runner.add_to_build_file("build-support", "python_library()") # A package module. Because there's only one source file belonging to the target, we should # not generate subtargets. rule_runner.create_file("tests/python/project_test/demo_test/__init__.py") rule_runner.add_to_build_file("tests/python/project_test/demo_test", "python_library()") # A module with both an implementation and a type stub. rule_runner.create_files("src/python/stubs", ["stub.py", "stub.pyi"]) rule_runner.add_to_build_file("src/python/stubs", "python_library()") # Check that plugin mappings work. Note that we duplicate one of the files with a normal # python_library(), which means neither the Protobuf nor Python targets should be used. rule_runner.create_files("src/python/protos", ["f1.proto", "f2.proto", "f2_pb2.py"]) rule_runner.add_to_build_file( "src/python/protos", dedent( """\ protobuf_library(name='protos') python_library(name='py') """ ), ) result = rule_runner.request(FirstPartyPythonModuleMapping, []) assert result == FirstPartyPythonModuleMapping( { "project.util.dirutil": ( Address("src/python/project/util", relative_file_path="dirutil.py"), ), "project.util.tarutil": ( Address("src/python/project/util", relative_file_path="tarutil.py"), ), "project_test.demo_test": ( Address("tests/python/project_test/demo_test", relative_file_path="__init__.py"), ), "protos.f1_pb2": ( Address("src/python/protos", relative_file_path="f1.proto", target_name="protos"), ), "stubs.stub": ( Address("src/python/stubs", relative_file_path="stub.py"), Address("src/python/stubs", relative_file_path="stub.pyi"), ), } )
def test_first_party_modules_mapping() -> None: util_addr = Address("src/python/util", relative_file_path="strutil.py") test_addr = Address("tests/python/project_test", relative_file_path="test.py") mapping = FirstPartyPythonModuleMapping( {"util.strutil": (util_addr,), "project_test.test": (test_addr,)} ) assert mapping.addresses_for_module("util.strutil") == (util_addr,) assert mapping.addresses_for_module("util.strutil.ensure_text") == (util_addr,) assert not mapping.addresses_for_module("util") assert mapping.addresses_for_module("project_test.test") == (test_addr,) assert mapping.addresses_for_module("project_test.test.TestDemo") == (test_addr,) assert not mapping.addresses_for_module("project_test.test.TestDemo.method") assert not mapping.addresses_for_module("project_test") assert not mapping.addresses_for_module("project.test")
def test_first_party_modules_mapping() -> None: root_addr = Address("", relative_file_path="root.py") util_addr = Address("src/python/util", relative_file_path="strutil.py") util_stubs_addr = Address("src/python/util", relative_file_path="strutil.pyi") test_addr = Address("tests/python/project_test", relative_file_path="test.py") mapping = FirstPartyPythonModuleMapping( mapping=FrozenDict({ "root": (root_addr, ), "util.strutil": (util_addr, util_stubs_addr), "project_test.test": (test_addr, ), }), ambiguous_modules=FrozenDict({ "ambiguous": (root_addr, util_addr), "util.ambiguous": (util_addr, test_addr) }), ) def assert_addresses( mod: str, expected: tuple[tuple[Address, ...], tuple[Address, ...]]) -> None: assert mapping.addresses_for_module(mod) == expected unknown = ((), ()) root = ((root_addr, ), ()) assert_addresses("root", root) assert_addresses("root.func", root) assert_addresses("root.submodule.func", unknown) util = ((util_addr, util_stubs_addr), ()) assert_addresses("util.strutil", util) assert_addresses("util.strutil.ensure_text", util) assert_addresses("util", unknown) test = ((test_addr, ), ()) assert_addresses("project_test.test", test) assert_addresses("project_test.test.TestDemo", test) assert_addresses("project_test", unknown) assert_addresses("project.test", unknown) ambiguous = ((), (root_addr, util_addr)) assert_addresses("ambiguous", ambiguous) assert_addresses("ambiguous.func", ambiguous) assert_addresses("ambiguous.submodule.func", unknown) util_ambiguous = ((), (util_addr, test_addr)) assert_addresses("util.ambiguous", util_ambiguous) assert_addresses("util.ambiguous.Foo", util_ambiguous) assert_addresses("util.ambiguous.Foo.method", unknown)
def test_map_first_party_modules_to_addresses(rule_runner: RuleRunner) -> None: rule_runner.set_options([ "--source-root-patterns=['src/python', 'tests/python', 'build-support']" ]) rule_runner.write_files({ "src/python/project/util/dirutil.py": "", "src/python/project/util/tarutil.py": "", "src/python/project/util/BUILD": "python_sources()", # A module with two owners, meaning that neither should be resolved. "src/python/two_owners.py": "", "src/python/BUILD": "python_sources()", "build-support/two_owners.py": "", "build-support/BUILD": "python_sources()", # A module with two owners that are type stubs. "src/python/stub_ambiguity/f.pyi": "", "src/python/stub_ambiguity/BUILD": "python_sources()", "build-support/stub_ambiguity/f.pyi": "", "build-support/stub_ambiguity/BUILD": "python_sources()", # A package module. "tests/python/project_test/demo_test/__init__.py": "", "tests/python/project_test/demo_test/BUILD": "python_sources()", # A module with both an implementation and a type stub. Even though the module is the # same, we special-case it to be legal for both file targets to be inferred. "src/python/stubs/stub.py": "", "src/python/stubs/stub.pyi": "", "src/python/stubs/BUILD": "python_sources()", # Check that plugin mappings work. Note that we duplicate one of the files with a normal # python_sources(), which means neither the Protobuf nor Python targets should be used. "src/python/protos/f1.proto": "", "src/python/protos/f2.proto": "", "src/python/protos/f2_pb2.py": "", "src/python/protos/BUILD": dedent("""\ protobuf_sources(name='protos') python_sources(name='py') """), # If a module is ambiguous within a particular implementation, which means that it's # not used in that implementation's final mapping, it should still trigger ambiguity # with another implementation. Here, we have ambiguity with the Protobuf targets, but # the Python file has no ambiguity with other Python files; the Protobuf ambiguity # needs to result in Python being ambiguous. "src/python/protos_ambiguous/f.proto": "", "src/python/protos_ambiguous/f_pb2.py": "", "src/python/protos_ambiguous/BUILD": dedent("""\ protobuf_sources(name='protos1') protobuf_sources(name='protos2') python_sources(name='py') """), }) result = rule_runner.request(FirstPartyPythonModuleMapping, []) assert result == FirstPartyPythonModuleMapping( mapping=FrozenDict({ "project.util.dirutil": (Address("src/python/project/util", relative_file_path="dirutil.py"), ), "project.util.tarutil": (Address("src/python/project/util", relative_file_path="tarutil.py"), ), "project_test.demo_test": (Address("tests/python/project_test/demo_test", relative_file_path="__init__.py"), ), "protos.f1_pb2": (Address("src/python/protos", relative_file_path="f1.proto", target_name="protos"), ), "stubs.stub": ( Address("src/python/stubs", relative_file_path="stub.py"), Address("src/python/stubs", relative_file_path="stub.pyi"), ), }), ambiguous_modules=FrozenDict({ "protos.f2_pb2": ( Address("src/python/protos", relative_file_path="f2.proto", target_name="protos"), Address("src/python/protos", relative_file_path="f2_pb2.py", target_name="py"), ), "protos_ambiguous.f_pb2": ( Address( "src/python/protos_ambiguous", relative_file_path="f.proto", target_name="protos1", ), Address( "src/python/protos_ambiguous", relative_file_path="f.proto", target_name="protos2", ), Address( "src/python/protos_ambiguous", relative_file_path="f_pb2.py", target_name="py", ), ), "stub_ambiguity.f": ( Address("build-support/stub_ambiguity", relative_file_path="f.pyi"), Address("src/python/stub_ambiguity", relative_file_path="f.pyi"), ), "two_owners": ( Address("build-support", relative_file_path="two_owners.py"), Address("src/python", relative_file_path="two_owners.py"), ), }), )
def test_first_party_modules_mapping() -> None: root_provider = ModuleProvider(Address("", relative_file_path="root.py"), ModuleProviderType.IMPL) util_provider = ModuleProvider( Address("src/python/util", relative_file_path="strutil.py"), ModuleProviderType.IMPL) util_stubs_provider = ModuleProvider( Address("src/python/util", relative_file_path="strutil.pyi"), ModuleProviderType.TYPE_STUB) test_provider = ModuleProvider( Address("tests/python/project_test", relative_file_path="test.py"), ModuleProviderType.IMPL) mapping = FirstPartyPythonModuleMapping( FrozenDict({ "default": FrozenDict({ "root": (root_provider, ), "util.strutil": (util_provider, util_stubs_provider), "project_test.test": (test_provider, ), "ambiguous": (root_provider, util_provider), "util.ambiguous": (util_provider, test_provider), "two_resolves": (root_provider, ), }), "another": FrozenDict({"two_resolves": (test_provider, )}), })) def assert_addresses(mod: str, expected: tuple[ModuleProvider, ...], *, resolve: str | None = None) -> None: assert mapping.providers_for_module(mod, resolve=resolve) == expected assert_addresses("root", (root_provider, )) assert_addresses("root.func", (root_provider, )) assert_addresses("root.submodule.func", ()) assert_addresses("util.strutil", (util_provider, util_stubs_provider)) assert_addresses("util.strutil.ensure_text", (util_provider, util_stubs_provider)) assert_addresses("util", ()) assert_addresses("project_test.test", (test_provider, )) assert_addresses("project_test.test.TestDemo", (test_provider, )) assert_addresses("project_test", ()) assert_addresses("project.test", ()) assert_addresses("ambiguous", (root_provider, util_provider)) assert_addresses("ambiguous.func", (root_provider, util_provider)) assert_addresses("ambiguous.submodule.func", ()) assert_addresses("util.ambiguous", (util_provider, test_provider)) assert_addresses("util.ambiguous.Foo", (util_provider, test_provider)) assert_addresses("util.ambiguous.Foo.method", ()) assert_addresses("two_resolves", (root_provider, test_provider), resolve=None) assert_addresses("two_resolves.foo", (root_provider, test_provider), resolve=None) assert_addresses("two_resolves.foo.bar", (), resolve=None) assert_addresses("two_resolves", (root_provider, ), resolve="default") assert_addresses("two_resolves", (test_provider, ), resolve="another")
def test_map_first_party_modules_to_addresses(rule_runner: RuleRunner) -> None: rule_runner.set_options([ "--source-root-patterns=['src/python', 'tests/python', 'build-support']", "--python-enable-resolves", "--python-resolves={'python-default': '', 'another-resolve': ''}", ]) rule_runner.write_files({ "src/python/project/util/dirutil.py": "", "src/python/project/util/tarutil.py": "", "src/python/project/util/BUILD": "python_sources(resolve='another-resolve')", # A module with multiple owners, including type stubs. "src/python/multiple_owners.py": "", "src/python/multiple_owners.pyi": "", "src/python/BUILD": "python_sources()", "build-support/multiple_owners.py": "", "build-support/BUILD": "python_sources()", # A package module. "tests/python/project_test/demo_test/__init__.py": "", "tests/python/project_test/demo_test/BUILD": "python_sources()", # Check that plugin mappings work. Note that we duplicate one of the files with a normal # python_source. "src/python/protos/f1.proto": "", "src/python/protos/f2.proto": "", "src/python/protos/f2_pb2.py": "", "src/python/protos/BUILD": dedent("""\ protobuf_sources(name='protos') python_source(name='py', source="f2_pb2.py") """), }) result = rule_runner.request(FirstPartyPythonModuleMapping, []) assert result == FirstPartyPythonModuleMapping( FrozenDict({ "another-resolve": FrozenDict({ "project.util.dirutil": (ModuleProvider( Address("src/python/project/util", relative_file_path="dirutil.py"), ModuleProviderType.IMPL, ), ), "project.util.tarutil": (ModuleProvider( Address("src/python/project/util", relative_file_path="tarutil.py"), ModuleProviderType.IMPL, ), ), }), "python-default": FrozenDict({ "multiple_owners": ( ModuleProvider( Address("build-support", relative_file_path="multiple_owners.py"), ModuleProviderType.IMPL, ), ModuleProvider( Address("src/python", relative_file_path="multiple_owners.py"), ModuleProviderType.IMPL, ), ModuleProvider( Address("src/python", relative_file_path="multiple_owners.pyi"), ModuleProviderType.TYPE_STUB, ), ), "project_test.demo_test": (ModuleProvider( Address( "tests/python/project_test/demo_test", relative_file_path="__init__.py", ), ModuleProviderType.IMPL, ), ), "protos.f1_pb2": (ModuleProvider( Address( "src/python/protos", relative_file_path="f1.proto", target_name="protos", ), ModuleProviderType.IMPL, ), ), "protos.f2_pb2": ( ModuleProvider( Address("src/python/protos", target_name="py"), ModuleProviderType.IMPL, ), ModuleProvider( Address( "src/python/protos", relative_file_path="f2.proto", target_name="protos", ), ModuleProviderType.IMPL, ), ), }), }))
def test_first_party_modules_mapping() -> None: root_addr = Address("", relative_file_path="root.py") util_addr = Address("src/python/util", relative_file_path="strutil.py") test_addr = Address("tests/python/project_test", relative_file_path="test.py") mapping = FirstPartyPythonModuleMapping( mapping=FrozenDict( {"root": (root_addr,), "util.strutil": (util_addr,), "project_test.test": (test_addr,)} ), ambiguous_modules=FrozenDict( {"ambiguous": (root_addr, util_addr), "util.ambiguous": (util_addr, test_addr)} ), ) assert mapping.addresses_for_module("root") == ((root_addr,), ()) assert mapping.addresses_for_module("root.func") == ((root_addr,), ()) assert mapping.addresses_for_module("root.submodule.func") == ((), ()) assert mapping.addresses_for_module("util.strutil") == ((util_addr,), ()) assert mapping.addresses_for_module("util.strutil.ensure_text") == ((util_addr,), ()) assert mapping.addresses_for_module("util") == ((), ()) assert mapping.addresses_for_module("project_test.test") == ((test_addr,), ()) assert mapping.addresses_for_module("project_test.test.TestDemo") == ((test_addr,), ()) assert mapping.addresses_for_module("project_test.test.TestDemo.method") == ((), ()) assert mapping.addresses_for_module("project_test") == ((), ()) assert mapping.addresses_for_module("project.test") == ((), ()) assert mapping.addresses_for_module("ambiguous") == ((), (root_addr, util_addr)) assert mapping.addresses_for_module("ambiguous.func") == ((), (root_addr, util_addr)) assert mapping.addresses_for_module("ambiguous.submodule.func") == ((), ()) assert mapping.addresses_for_module("util.ambiguous") == ((), (util_addr, test_addr)) assert mapping.addresses_for_module("util.ambiguous.Foo") == ((), (util_addr, test_addr)) assert mapping.addresses_for_module("util.ambiguous.Foo.method") == ((), ())
def test_map_first_party_modules_to_addresses(rule_runner: RuleRunner) -> None: rule_runner.set_options( ["--source-root-patterns=['src/python', 'tests/python', 'build-support']"] ) # Two modules belonging to the same target. We should generate subtargets for each file. rule_runner.create_files("src/python/project/util", ["dirutil.py", "tarutil.py"]) rule_runner.add_to_build_file("src/python/project/util", "python_library()") # A module with two owners, meaning that neither should be resolved. rule_runner.create_file("src/python/two_owners.py") rule_runner.add_to_build_file("src/python", "python_library()") rule_runner.create_file("build-support/two_owners.py") rule_runner.add_to_build_file("build-support", "python_library()") # A package module. Because there's only one source file belonging to the target, we should # not generate subtargets. rule_runner.create_file("tests/python/project_test/demo_test/__init__.py") rule_runner.add_to_build_file("tests/python/project_test/demo_test", "python_library()") # A module with both an implementation and a type stub. Even though the module is the same, we # special-case it to be legal for both file targets to be inferred. rule_runner.create_files("src/python/stubs", ["stub.py", "stub.pyi"]) rule_runner.add_to_build_file("src/python/stubs", "python_library()") # Check that plugin mappings work. Note that we duplicate one of the files with a normal # python_library(), which means neither the Protobuf nor Python targets should be used. rule_runner.create_files("src/python/protos", ["f1.proto", "f2.proto", "f2_pb2.py"]) rule_runner.add_to_build_file( "src/python/protos", dedent( """\ protobuf_library(name='protos') python_library(name='py') """ ), ) # If a module is ambiguous within a particular implementation, which means that it's not used # in that implementation's final mapping, it should still trigger ambiguity with another # implementation. Here, we have ambiguity with the Protobuf targets, but the Python file has # no ambiguity with other Python files; the Protobuf ambiguity needs to result in Python # being ambiguous. rule_runner.create_files("src/python/protos_ambiguous", ["f.proto", "f_pb2.py"]) rule_runner.add_to_build_file( "src/python/protos_ambiguous", dedent( """\ protobuf_library(name='protos1') protobuf_library(name='protos2') python_library(name='py') """ ), ) result = rule_runner.request(FirstPartyPythonModuleMapping, []) assert result == FirstPartyPythonModuleMapping( mapping=FrozenDict( { "project.util.dirutil": ( Address("src/python/project/util", relative_file_path="dirutil.py"), ), "project.util.tarutil": ( Address("src/python/project/util", relative_file_path="tarutil.py"), ), "project_test.demo_test": ( Address( "tests/python/project_test/demo_test", relative_file_path="__init__.py" ), ), "protos.f1_pb2": ( Address( "src/python/protos", relative_file_path="f1.proto", target_name="protos" ), ), "stubs.stub": ( Address("src/python/stubs", relative_file_path="stub.py"), Address("src/python/stubs", relative_file_path="stub.pyi"), ), } ), ambiguous_modules=FrozenDict( { "protos.f2_pb2": ( Address( "src/python/protos", relative_file_path="f2.proto", target_name="protos" ), Address("src/python/protos", relative_file_path="f2_pb2.py", target_name="py"), ), "protos_ambiguous.f_pb2": ( Address( "src/python/protos_ambiguous", relative_file_path="f.proto", target_name="protos1", ), Address( "src/python/protos_ambiguous", relative_file_path="f.proto", target_name="protos2", ), Address( "src/python/protos_ambiguous", relative_file_path="f_pb2.py", target_name="py", ), ), "two_owners": ( Address("build-support", relative_file_path="two_owners.py"), Address("src/python", relative_file_path="two_owners.py"), ), } ), )