Skip to content

Commit 25d4227

Browse files
committed
wip: reimplement namespace pkg filepath calc in starlark
With this PR I would like to facilitate the implementation of the venv layouts because we can in theory take the `srcs` and the `data` within the `py_library` and then use the `expand_template` to write the extra Python files if the namespace_pkgs flag is enabled. This is WIP so that maintainers can hop in if they have time. TODO: - [ ] Do the ctx.actions.expand_template based on the output from the reimplementation - [ ] Thread the namespace_pkgs attr - [ ] Remove Python code? Put under pipstar? Work towards #2156
1 parent d6af2b7 commit 25d4227

File tree

3 files changed

+213
-0
lines changed

3 files changed

+213
-0
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""Utilities to get where we should write namespace pkg paths."""
2+
3+
EXTS = [
4+
".py",
5+
".pyd",
6+
".so",
7+
".pyc",
8+
]
9+
10+
def _get_files(files, ignored_dirnames = []):
11+
dirs = {}
12+
ignored = {i: None for i in ignored_dirnames}
13+
for file in files:
14+
dirname, _, filename = file.rpartition("/")
15+
16+
if filename == "__init__.py":
17+
ignored[dirname] = None
18+
dirname, _, _ = dirname.rpartition("/")
19+
elif filename.endswith(EXTS[0]):
20+
pass
21+
elif filename.endswith(EXTS[1]):
22+
pass
23+
elif filename.endswith(EXTS[2]):
24+
pass
25+
elif filename.endswith(EXTS[3]):
26+
pass
27+
else:
28+
continue
29+
30+
if dirname in dirs or not dirname:
31+
continue
32+
33+
dir_path = "."
34+
for dir_name in dirname.split("/"):
35+
dir_path = "{}/{}".format(dir_path, dir_name)
36+
dirs[dir_path[2:]] = None
37+
38+
return sorted([d for d in dirs if d not in ignored])
39+
40+
namespace_pkgs = struct(
41+
get_files = _get_files,
42+
)

tests/pypi/namespace_pkgs/BUILD.bazel

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
load(":namespace_pkgs_tests.bzl", "namespace_pkgs_test_suite")
2+
3+
namespace_pkgs_test_suite(
4+
name = "namespace_pkgs_tests",
5+
)
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
""
2+
3+
load("@rules_testing//lib:analysis_test.bzl", "test_suite")
4+
load("//python/private/pypi:namespace_pkgs.bzl", "namespace_pkgs") # buildifier: disable=bzl-visibility
5+
6+
_tests = []
7+
8+
def test_in_current_dir(env):
9+
files = [
10+
"foo/bar/biz.py",
11+
"foo/bee/boo.py",
12+
"foo/buu/__init__.py",
13+
"foo/buu/bii.py",
14+
]
15+
got = namespace_pkgs.get_files(files)
16+
expected = [
17+
"foo",
18+
"foo/bar",
19+
"foo/bee",
20+
]
21+
env.expect.that_collection(got).contains_exactly(expected)
22+
23+
_tests.append(test_in_current_dir)
24+
25+
def test_find_correct_namespace_packages(env):
26+
files = [
27+
"foo/bar/biz.py",
28+
"foo/bee/boo.py",
29+
"foo/buu/__init__.py",
30+
"foo/buu/bii.py",
31+
]
32+
33+
got = namespace_pkgs.get_files(files)
34+
expected = [
35+
"foo",
36+
"foo/bar",
37+
"foo/bee",
38+
]
39+
env.expect.that_collection(got).contains_exactly(expected)
40+
41+
_tests.append(test_find_correct_namespace_packages)
42+
43+
def test_ignores_empty_directories(_):
44+
# because globs do not add directories, this test is not needed
45+
pass
46+
47+
_tests.append(test_ignores_empty_directories)
48+
49+
def test_empty_case(env):
50+
files = [
51+
"foo/__init__.py",
52+
"foo/bar/__init__.py",
53+
"foo/bar/biz.py",
54+
]
55+
56+
got = namespace_pkgs.get_files(files)
57+
expected = []
58+
env.expect.that_collection(got).contains_exactly(expected)
59+
60+
_tests.append(test_empty_case)
61+
62+
def test_ignores_non_module_files_in_directories(env):
63+
files = [
64+
"foo/__init__.pyi",
65+
"foo/py.typed",
66+
]
67+
68+
got = namespace_pkgs.get_files(files)
69+
expected = []
70+
env.expect.that_collection(got).contains_exactly(expected)
71+
72+
_tests.append(test_ignores_non_module_files_in_directories)
73+
74+
def test_parent_child_relationship_of_namespace_pkgs(env):
75+
files = [
76+
"foo/bar/biff/my_module.py",
77+
"foo/bar/biff/another_module.py",
78+
]
79+
80+
got = namespace_pkgs.get_files(files)
81+
expected = [
82+
"foo",
83+
"foo/bar",
84+
"foo/bar/biff",
85+
]
86+
env.expect.that_collection(got).contains_exactly(expected)
87+
88+
_tests.append(test_parent_child_relationship_of_namespace_pkgs)
89+
90+
def test_parent_child_relationship_of_namespace_and_standard_pkgs(env):
91+
files = [
92+
"foo/bar/biff/__init__.py",
93+
"foo/bar/biff/another_module.py",
94+
]
95+
96+
got = namespace_pkgs.get_files(files)
97+
expected = [
98+
"foo",
99+
"foo/bar",
100+
]
101+
env.expect.that_collection(got).contains_exactly(expected)
102+
103+
_tests.append(test_parent_child_relationship_of_namespace_and_standard_pkgs)
104+
105+
def test_parent_child_relationship_of_namespace_and_nested_standard_pkgs(env):
106+
files = [
107+
"foo/bar/__init__.py",
108+
"foo/bar/biff/another_module.py",
109+
"foo/bar/biff/__init__.py",
110+
"foo/bar/boof/big_module.py",
111+
"foo/bar/boof/__init__.py",
112+
"fim/in_a_ns_pkg.py",
113+
]
114+
115+
got = namespace_pkgs.get_files(files)
116+
expected = [
117+
"foo",
118+
"fim",
119+
]
120+
env.expect.that_collection(got).contains_exactly(expected)
121+
122+
_tests.append(test_parent_child_relationship_of_namespace_and_nested_standard_pkgs)
123+
124+
def test_recognized_all_nonstandard_module_types(env):
125+
files = [
126+
"ayy/my_module.pyc",
127+
"bee/ccc/dee/eee.so",
128+
"eff/jee/aych.pyd",
129+
]
130+
131+
expected = [
132+
"ayy",
133+
"bee",
134+
"bee/ccc",
135+
"bee/ccc/dee",
136+
"eff",
137+
"eff/jee",
138+
]
139+
got = namespace_pkgs.get_files(files)
140+
env.expect.that_collection(got).contains_exactly(expected)
141+
142+
_tests.append(test_recognized_all_nonstandard_module_types)
143+
144+
def test_skips_ignored_directories(env):
145+
files = [
146+
"foo/boo/my_module.py",
147+
"foo/bar/another_module.py",
148+
]
149+
150+
expected = [
151+
"foo",
152+
"foo/bar",
153+
]
154+
got = namespace_pkgs.get_files(
155+
files,
156+
ignored_dirnames = ["foo/boo"],
157+
)
158+
env.expect.that_collection(got).contains_exactly(expected)
159+
160+
_tests.append(test_skips_ignored_directories)
161+
162+
def namespace_pkgs_test_suite(name):
163+
test_suite(
164+
name = name,
165+
basic_tests = _tests,
166+
)

0 commit comments

Comments
 (0)