fix(pypi): namespace_pkgs should pass correct arguments (#3026)

It seems that the only function that did not have unit tests have bugs
and the integration tests did not catch it because we weren't creating
namespacepkg `__init__.py` files.

This change fixes the bug, adds a unit test for the remaining untested
function.

Fixes #3023

Co-authored-by: Richard Levasseur <richardlev@gmail.com>
(cherry picked from commit 49780276797ecdb22afeda0b8c72a680a3c0b41a)
diff --git a/python/private/pypi/namespace_pkgs.bzl b/python/private/pypi/namespace_pkgs.bzl
index bf4689a..be6244e 100644
--- a/python/private/pypi/namespace_pkgs.bzl
+++ b/python/private/pypi/namespace_pkgs.bzl
@@ -59,25 +59,32 @@
 
     return sorted([d for d in dirs if d not in ignored])
 
-def create_inits(**kwargs):
+def create_inits(*, srcs, ignored_dirnames = [], root = None, copy_file = copy_file, **kwargs):
     """Create init files and return the list to be included `py_library` srcs.
 
     Args:
-        **kwargs: passed to {obj}`get_files`.
+        srcs: {type}`src` a list of files to be passed to {bzl:obj}`py_library`
+            as `srcs` and `data`. This is usually a result of a {obj}`glob`.
+        ignored_dirnames: {type}`str` a list of patterns to ignore.
+        root: {type}`str` the prefix to use as the root.
+        copy_file: the `copy_file` rule to copy files in build context.
+        **kwargs: passed to {obj}`copy_file`.
 
     Returns:
         {type}`list[str]` to be included as part of `py_library`.
     """
-    srcs = []
-    for out in get_files(**kwargs):
+    ret = []
+    for i, out in enumerate(get_files(srcs = srcs, ignored_dirnames = ignored_dirnames, root = root)):
         src = "{}/__init__.py".format(out)
-        srcs.append(srcs)
+        ret.append(src)
 
         copy_file(
-            name = "_cp_{}_namespace".format(out),
+            # For the target name, use a number instead of trying to convert an output
+            # path into a valid label.
+            name = "_cp_{}_namespace".format(i),
             src = _TEMPLATE,
             out = src,
             **kwargs
         )
 
-    return srcs
+    return ret
diff --git a/tests/pypi/namespace_pkgs/namespace_pkgs_tests.bzl b/tests/pypi/namespace_pkgs/namespace_pkgs_tests.bzl
index 7ac938f..9c382d0 100644
--- a/tests/pypi/namespace_pkgs/namespace_pkgs_tests.bzl
+++ b/tests/pypi/namespace_pkgs/namespace_pkgs_tests.bzl
@@ -1,7 +1,7 @@
 ""
 
 load("@rules_testing//lib:analysis_test.bzl", "test_suite")
-load("//python/private/pypi:namespace_pkgs.bzl", "get_files")  # buildifier: disable=bzl-visibility
+load("//python/private/pypi:namespace_pkgs.bzl", "create_inits", "get_files")  # buildifier: disable=bzl-visibility
 
 _tests = []
 
@@ -160,6 +160,45 @@
 
 _tests.append(test_skips_ignored_directories)
 
+def _test_create_inits(env):
+    srcs = [
+        "nested/root/foo/bar/biz.py",
+        "nested/root/foo/bee/boo.py",
+        "nested/root/foo/buu/__init__.py",
+        "nested/root/foo/buu/bii.py",
+    ]
+    copy_file_calls = []
+    template = Label("//python/private/pypi:namespace_pkg_tmpl.py")
+
+    got = create_inits(
+        srcs = srcs,
+        root = "nested/root",
+        copy_file = lambda **kwargs: copy_file_calls.append(kwargs),
+    )
+    env.expect.that_collection(got).contains_exactly([
+        call["out"]
+        for call in copy_file_calls
+    ])
+    env.expect.that_collection(copy_file_calls).contains_exactly([
+        {
+            "name": "_cp_0_namespace",
+            "out": "nested/root/foo/__init__.py",
+            "src": template,
+        },
+        {
+            "name": "_cp_1_namespace",
+            "out": "nested/root/foo/bar/__init__.py",
+            "src": template,
+        },
+        {
+            "name": "_cp_2_namespace",
+            "out": "nested/root/foo/bee/__init__.py",
+            "src": template,
+        },
+    ])
+
+_tests.append(_test_create_inits)
+
 def namespace_pkgs_test_suite(name):
     test_suite(
         name = name,