Add python_library -> py_library bp2build support

Bug: 196091681
Test: bp2build/python_library_conversion_test.go
Test: build/bazel/ci/mixed_{libc,droid}.sh
Change-Id: Ice87d75533c97fd9c139dc59de09a039e2713a01
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 78e3a74..b1ccc96 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -42,6 +42,7 @@
         "performance_test.go",
         "prebuilt_etc_conversion_test.go",
         "python_binary_conversion_test.go",
+        "python_library_conversion_test.go",
         "sh_conversion_test.go",
         "testing.go",
     ],
diff --git a/bp2build/python_library_conversion_test.go b/bp2build/python_library_conversion_test.go
new file mode 100644
index 0000000..e337965
--- /dev/null
+++ b/bp2build/python_library_conversion_test.go
@@ -0,0 +1,134 @@
+package bp2build
+
+import (
+	"testing"
+
+	"android/soong/python"
+)
+
+func TestPythonLibrarySimple(t *testing.T) {
+	runBp2BuildTestCaseSimple(t, bp2buildTestCase{
+		description:                        "simple python_library converts to a native py_library",
+		moduleTypeUnderTest:                "python_library",
+		moduleTypeUnderTestFactory:         python.PythonLibraryFactory,
+		moduleTypeUnderTestBp2BuildMutator: python.PythonLibraryBp2Build,
+		filesystem: map[string]string{
+			"a.py":           "",
+			"b/c.py":         "",
+			"b/d.py":         "",
+			"b/e.py":         "",
+			"files/data.txt": "",
+		},
+		blueprint: `python_library {
+    name: "foo",
+    srcs: ["**/*.py"],
+    exclude_srcs: ["b/e.py"],
+    data: ["files/data.txt",],
+    bazel_module: { bp2build_available: true },
+}
+`,
+		expectedBazelTargets: []string{`py_library(
+    name = "foo",
+    data = ["files/data.txt"],
+    srcs = [
+        "a.py",
+        "b/c.py",
+        "b/d.py",
+    ],
+    srcs_version = "PY3",
+)`,
+		},
+	})
+}
+
+func TestPythonLibraryPy2(t *testing.T) {
+	runBp2BuildTestCaseSimple(t, bp2buildTestCase{
+		description:                        "py2 python_library",
+		moduleTypeUnderTest:                "python_library",
+		moduleTypeUnderTestFactory:         python.PythonLibraryFactory,
+		moduleTypeUnderTestBp2BuildMutator: python.PythonLibraryBp2Build,
+		blueprint: `python_library {
+    name: "foo",
+    srcs: ["a.py"],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    },
+
+    bazel_module: { bp2build_available: true },
+}
+`,
+		expectedBazelTargets: []string{`py_library(
+    name = "foo",
+    srcs = ["a.py"],
+    srcs_version = "PY2",
+)`,
+		},
+	})
+}
+
+func TestPythonLibraryPy3(t *testing.T) {
+	runBp2BuildTestCaseSimple(t, bp2buildTestCase{
+		description:                        "py3 python_library",
+		moduleTypeUnderTest:                "python_library",
+		moduleTypeUnderTestFactory:         python.PythonLibraryFactory,
+		moduleTypeUnderTestBp2BuildMutator: python.PythonLibraryBp2Build,
+		blueprint: `python_library {
+    name: "foo",
+    srcs: ["a.py"],
+    version: {
+        py2: {
+            enabled: false,
+        },
+        py3: {
+            enabled: true,
+        },
+    },
+
+    bazel_module: { bp2build_available: true },
+}
+`,
+		expectedBazelTargets: []string{
+			`py_library(
+    name = "foo",
+    srcs = ["a.py"],
+    srcs_version = "PY3",
+)`,
+		},
+	})
+}
+
+func TestPythonLibraryPyBoth(t *testing.T) {
+	runBp2BuildTestCaseSimple(t, bp2buildTestCase{
+		description:                        "py3 python_library",
+		moduleTypeUnderTest:                "python_library",
+		moduleTypeUnderTestFactory:         python.PythonLibraryFactory,
+		moduleTypeUnderTestBp2BuildMutator: python.PythonLibraryBp2Build,
+		blueprint: `python_library {
+    name: "foo",
+    srcs: ["a.py"],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: true,
+        },
+    },
+
+    bazel_module: { bp2build_available: true },
+}
+`,
+		expectedBazelTargets: []string{
+			// srcs_version is PY2ANDPY3 by default.
+			`py_library(
+    name = "foo",
+    srcs = ["a.py"],
+)`,
+		},
+	})
+}
diff --git a/python/library.go b/python/library.go
index 9663b3c..c255190 100644
--- a/python/library.go
+++ b/python/library.go
@@ -17,11 +17,16 @@
 // This file contains the module types for building Python library.
 
 import (
+	"fmt"
+
 	"android/soong/android"
+	"android/soong/bazel"
+	"github.com/google/blueprint/proptools"
 )
 
 func init() {
 	registerPythonLibraryComponents(android.InitRegistrationContext)
+	android.RegisterBp2BuildMutator("python_library", PythonLibraryBp2Build)
 }
 
 func registerPythonLibraryComponents(ctx android.RegistrationContext) {
@@ -35,8 +40,63 @@
 	return module.init()
 }
 
+type bazelPythonLibraryAttributes struct {
+	Srcs         bazel.LabelListAttribute
+	Data         bazel.LabelListAttribute
+	Srcs_version string
+}
+
+func PythonLibraryBp2Build(ctx android.TopDownMutatorContext) {
+	m, ok := ctx.Module().(*Module)
+	if !ok || !m.ConvertWithBp2build(ctx) {
+		return
+	}
+
+	// a Module can be something other than a python_library
+	if ctx.ModuleType() != "python_library" {
+		return
+	}
+
+	// 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
+	// mutator. This is sufficient for very simple python_library modules under
+	// Bionic.
+	py3Enabled := proptools.BoolDefault(m.properties.Version.Py3.Enabled, true)
+	py2Enabled := proptools.BoolDefault(m.properties.Version.Py2.Enabled, false)
+	var python_version string
+	if py2Enabled && !py3Enabled {
+		python_version = "PY2"
+	} else if !py2Enabled && py3Enabled {
+		python_version = "PY3"
+	} else if !py2Enabled && !py3Enabled {
+		panic(fmt.Errorf(
+			"error for '%s' module: bp2build's python_library converter doesn't understand having "+
+				"neither py2 nor py3 enabled", m.Name()))
+	} else {
+		// do nothing, since python_version defaults to PY2ANDPY3
+	}
+
+	srcs := android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
+	data := android.BazelLabelForModuleSrc(ctx, m.properties.Data)
+
+	attrs := &bazelPythonLibraryAttributes{
+		Srcs:         bazel.MakeLabelListAttribute(srcs),
+		Data:         bazel.MakeLabelListAttribute(data),
+		Srcs_version: python_version,
+	}
+
+	props := bazel.BazelTargetModuleProperties{
+		// Use the native py_library rule.
+		Rule_class: "py_library",
+	}
+
+	ctx.CreateBazelTargetModule(m.Name(), props, attrs)
+}
+
 func PythonLibraryFactory() android.Module {
 	module := newModule(android.HostAndDeviceSupported, android.MultilibBoth)
 
+	android.InitBazelModule(module)
+
 	return module.init()
 }