Add bp2build converter for python protobuf files

Bug: 196084681
Test: b run //build/bazel/examples/python/protobuf:build_bazel_examples_python_protobuf_main --config=linux_x86_64
Change-Id: I4d806902d262351231f64686a5d24513a25d9749
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 69703d1..8f1f29f 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -46,6 +46,7 @@
 		"bootable/recovery/tools/recovery_l10n": Bp2BuildDefaultTrue,
 		"build/bazel/examples/apex/minimal":     Bp2BuildDefaultTrueRecursively,
 		"build/bazel/examples/soong_config_variables":        Bp2BuildDefaultTrueRecursively,
+		"build/bazel/examples/python":                        Bp2BuildDefaultTrueRecursively,
 		"build/make/target/product/security":                 Bp2BuildDefaultTrue,
 		"build/make/tools/signapk":                           Bp2BuildDefaultTrue,
 		"build/soong":                                        Bp2BuildDefaultTrue,
@@ -322,9 +323,7 @@
 		"libbase_ndk", // TODO(b/186826477): fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
 
 		// python protos
-		"libprotobuf-python",                           // TODO(b/196084681): contains .proto sources
-		"apex_build_info_proto", "apex_manifest_proto", // TODO(b/196084681): a python lib with proto sources
-		"linker_config_proto", // TODO(b/196084681): contains .proto sources
+		"libprotobuf-python", // Has a handcrafted alternative
 
 		// genrule incompatibilities
 		"brotli-fuzzer-corpus",                                       // TODO(b/202015218): outputs are in location incompatible with bazel genrule handling.
diff --git a/bazel/properties.go b/bazel/properties.go
index f956031..41bcaca 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -652,6 +652,11 @@
 	}
 }
 
+// MakeSingleLabelListAttribute initializes a LabelListAttribute as a non-arch specific list with 1 element, the given Label.
+func MakeSingleLabelListAttribute(value Label) LabelListAttribute {
+	return MakeLabelListAttribute(MakeLabelList([]Label{value}))
+}
+
 func (lla *LabelListAttribute) SetValue(list LabelList) {
 	lla.SetSelectValue(NoConfigAxis, "", list)
 }
diff --git a/bp2build/python_library_conversion_test.go b/bp2build/python_library_conversion_test.go
index 66c2290..f51f106 100644
--- a/bp2build/python_library_conversion_test.go
+++ b/bp2build/python_library_conversion_test.go
@@ -305,3 +305,46 @@
 		},
 	})
 }
+
+func TestPythonLibraryWithProtobufs(t *testing.T) {
+	runPythonLibraryTestCases(t, pythonLibBp2BuildTestCase{
+		description: "test %s protobuf",
+		filesystem: map[string]string{
+			"dir/mylib.py":      "",
+			"dir/myproto.proto": "",
+		},
+		blueprint: `%s {
+					 name: "foo",
+					 srcs: [
+						"dir/mylib.py",
+						"dir/myproto.proto",
+					 ],
+				 }`,
+		expectedBazelTargets: []testBazelTarget{
+			{
+				typ:  "proto_library",
+				name: "foo_proto",
+				attrs: attrNameToString{
+					"srcs": `["dir/myproto.proto"]`,
+				},
+			},
+			{
+				typ:  "py_proto_library",
+				name: "foo_py_proto",
+				attrs: attrNameToString{
+					"deps": `[":foo_proto"]`,
+				},
+			},
+			{
+				typ:  "py_library",
+				name: "foo",
+				attrs: attrNameToString{
+					"srcs":         `["dir/mylib.py"]`,
+					"srcs_version": `"PY3"`,
+					"imports":      `["."]`,
+					"deps":         `[":foo_py_proto"]`,
+				},
+			},
+		},
+	})
+}
diff --git a/python/library.go b/python/library.go
index 3a27591..5071b74 100644
--- a/python/library.go
+++ b/python/library.go
@@ -50,6 +50,10 @@
 	Srcs_version *string
 }
 
+type bazelPythonProtoLibraryAttributes struct {
+	Deps bazel.LabelListAttribute
+}
+
 func pythonLibBp2Build(ctx android.TopDownMutatorContext, m *Module) {
 	// TODO(b/182306917): this doesn't fully handle all nested props versioned
 	// by the python version, which would have been handled by the version split
@@ -96,6 +100,7 @@
 	}
 
 	baseAttrs := m.makeArchVariantBaseAttributes(ctx)
+
 	attrs := &bazelPythonLibraryAttributes{
 		Srcs:         baseAttrs.Srcs,
 		Deps:         baseAttrs.Deps,
diff --git a/python/python.go b/python/python.go
index b100cc3..7e4cb83 100644
--- a/python/python.go
+++ b/python/python.go
@@ -207,6 +207,29 @@
 			}
 		}
 	}
+
+	partitionedSrcs := bazel.PartitionLabelListAttribute(ctx, &attrs.Srcs, bazel.LabelPartitions{
+		"proto": android.ProtoSrcLabelPartition,
+		"py":    bazel.LabelPartition{Keep_remainder: true},
+	})
+	attrs.Srcs = partitionedSrcs["py"]
+
+	if !partitionedSrcs["proto"].IsEmpty() {
+		protoInfo, _ := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, partitionedSrcs["proto"])
+		protoLabel := bazel.Label{Label: ":" + protoInfo.Name}
+
+		pyProtoLibraryName := m.Name() + "_py_proto"
+		ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
+			Rule_class:        "py_proto_library",
+			Bzl_load_location: "//build/bazel/rules/python:py_proto.bzl",
+		}, android.CommonAttributes{
+			Name: pyProtoLibraryName,
+		}, &bazelPythonProtoLibraryAttributes{
+			Deps: bazel.MakeSingleLabelListAttribute(protoLabel),
+		})
+
+		attrs.Deps.Add(bazel.MakeLabelAttribute(":" + pyProtoLibraryName))
+	}
 	return attrs
 }