Skip to content

Commit 8d78e18

Browse files
committed
mock glob
1 parent 8c9e03a commit 8d78e18

File tree

2 files changed

+165
-108
lines changed

2 files changed

+165
-108
lines changed

python/private/pypi/whl_library_targets.bzl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ load(
3030
"WHEEL_FILE_IMPL_LABEL",
3131
"WHEEL_FILE_PUBLIC_LABEL",
3232
)
33-
load(":namespace_pkgs.bzl", "create_inits")
33+
load(":namespace_pkgs.bzl", _create_inits = "create_inits")
3434
load(":pep508_deps.bzl", "deps")
3535

3636
def whl_library_targets_from_requires(
@@ -120,6 +120,7 @@ def whl_library_targets(
120120
py_binary = py_binary,
121121
py_library = py_library,
122122
env_marker_setting = env_marker_setting,
123+
create_inits = _create_inits,
123124
)):
124125
"""Create all of the whl_library targets.
125126
@@ -334,7 +335,7 @@ def whl_library_targets(
334335
if not enable_implicit_namespace_pkgs:
335336
srcs = srcs + getattr(native, "select", select)({
336337
Label("//python/config_settings:is_venvs_site_packages"): [],
337-
"//conditions:default": create_inits(
338+
"//conditions:default": rules.create_inits(
338339
srcs = srcs + data + pyi_srcs,
339340
ignored_dirnames = [], # If you need to ignore certain folders, you can patch rules_python here to do so.
340341
root = "site-packages",

tests/pypi/whl_library_targets/whl_library_targets_tests.bzl

Lines changed: 162 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,14 @@
1616

1717
load("@rules_testing//lib:test_suite.bzl", "test_suite")
1818
load("//python/private:glob_excludes.bzl", "glob_excludes") # buildifier: disable=bzl-visibility
19-
load("//python/private/pypi:whl_library_targets.bzl", _whl_library_targets = "whl_library_targets", _whl_library_targets_from_requires = "whl_library_targets_from_requires") # buildifier: disable=bzl-visibility
19+
load(
20+
"//python/private/pypi:whl_library_targets.bzl",
21+
"whl_library_targets",
22+
"whl_library_targets_from_requires",
23+
) # buildifier: disable=bzl-visibility
2024

2125
_tests = []
2226

23-
def whl_library_targets(**kwargs):
24-
# Let's skip testing this for now
25-
_whl_library_targets(enable_implicit_namespace_pkgs = True, **kwargs)
26-
27-
def whl_library_targets_from_requires(**kwargs):
28-
# Let's skip testing this for now
29-
_whl_library_targets_from_requires(enable_implicit_namespace_pkgs = True, **kwargs)
30-
3127
def _test_filegroups(env):
3228
calls = []
3329

@@ -190,6 +186,12 @@ def _test_whl_and_library_deps_from_requires(env):
190186
py_library_calls = []
191187
env_marker_setting_calls = []
192188

189+
mock_glob = _mock_glob()
190+
191+
mock_glob.results.append(["site-packages/foo/SRCS.py"])
192+
mock_glob.results.append(["site-packages/foo/DATA.txt"])
193+
mock_glob.results.append(["site-packages/foo/PYI.pyi"])
194+
193195
whl_library_targets_from_requires(
194196
name = "foo-0-py3-none-any.whl",
195197
metadata_name = "Foo",
@@ -208,12 +210,13 @@ def _test_whl_and_library_deps_from_requires(env):
208210
native = struct(
209211
filegroup = lambda **kwargs: filegroup_calls.append(kwargs),
210212
config_setting = lambda **_: None,
211-
glob = _glob,
213+
glob = mock_glob.glob,
212214
select = _select,
213215
),
214216
rules = struct(
215217
py_library = lambda **kwargs: py_library_calls.append(kwargs),
216218
env_marker_setting = lambda **kwargs: env_marker_setting_calls.append(kwargs),
219+
create_inits = lambda *args, **kwargs: ["_create_inits_target"],
217220
),
218221
)
219222

@@ -228,34 +231,51 @@ def _test_whl_and_library_deps_from_requires(env):
228231
"visibility": ["//visibility:public"],
229232
},
230233
]) # buildifier: @unsorted-dict-items
231-
env.expect.that_collection(py_library_calls).contains_exactly([
232-
{
233-
"name": "pkg",
234-
"srcs": _glob(
235-
["site-packages/**/*.py"],
236-
exclude = [],
237-
allow_empty = True,
238-
),
239-
"pyi_srcs": _glob(["site-packages/**/*.pyi"], allow_empty = True),
240-
"data": [] + _glob(
241-
["site-packages/**/*"],
242-
exclude = [
243-
"**/*.py",
244-
"**/*.pyc",
245-
"**/*.pyc.*",
246-
"**/*.dist-info/RECORD",
247-
] + glob_excludes.version_dependent_exclusions(),
248-
),
249-
"imports": ["site-packages"],
250-
"deps": ["@pypi//bar:pkg"] + _select({
251-
":is_include_bar_baz_true": ["@pypi//bar_baz:pkg"],
252-
"//conditions:default": [],
253-
}),
254-
"tags": ["pypi_name=Foo", "pypi_version=0"],
255-
"visibility": ["//visibility:public"],
256-
"experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"),
257-
},
258-
]) # buildifier: @unsorted-dict-items
234+
235+
env.expect.that_collection(py_library_calls).has_size(1)
236+
if len(py_library_calls) != 1:
237+
return
238+
py_library_call = py_library_calls[0]
239+
240+
env.expect.that_dict(py_library_call).contains_exactly({
241+
"name": "pkg",
242+
"srcs": ["site-packages/foo/SRCS.py"] + _select({
243+
Label("//python/config_settings:is_venvs_site_packages"): [],
244+
"//conditions:default": ["_create_inits_target"],
245+
}),
246+
"pyi_srcs": ["site-packages/foo/PYI.pyi"],
247+
"data": ["site-packages/foo/DATA.txt"],
248+
"imports": ["site-packages"],
249+
"deps": ["@pypi//bar:pkg"] + _select({
250+
":is_include_bar_baz_true": ["@pypi//bar_baz:pkg"],
251+
"//conditions:default": [],
252+
}),
253+
"tags": ["pypi_name=Foo", "pypi_version=0"],
254+
"visibility": ["//visibility:public"],
255+
"experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"),
256+
}) # buildifier: @unsorted-dict-items
257+
258+
env.expect.that_collection(mock_glob.calls).contains_exactly([
259+
# srcs call
260+
_glob_call(
261+
["site-packages/**/*.py"],
262+
exclude = [],
263+
allow_empty = True,
264+
),
265+
# data call
266+
_glob_call(
267+
["site-packages/**/*"],
268+
exclude = [
269+
"**/*.py",
270+
"**/*.pyc",
271+
"**/*.pyc.*",
272+
"**/*.dist-info/RECORD",
273+
] + glob_excludes.version_dependent_exclusions(),
274+
),
275+
# pyi call
276+
_glob_call(["site-packages/**/*.pyi"], allow_empty = True),
277+
])
278+
259279
env.expect.that_collection(env_marker_setting_calls).contains_exactly([
260280
{
261281
"name": "include_bar_baz",
@@ -269,6 +289,10 @@ _tests.append(_test_whl_and_library_deps_from_requires)
269289
def _test_whl_and_library_deps(env):
270290
filegroup_calls = []
271291
py_library_calls = []
292+
mock_glob = _mock_glob()
293+
mock_glob.results.append(["site-packages/foo/SRCS.py"])
294+
mock_glob.results.append(["site-packages/foo/DATA.txt"])
295+
mock_glob.results.append(["site-packages/foo/PYI.pyi"])
272296

273297
whl_library_targets(
274298
name = "foo.whl",
@@ -290,11 +314,12 @@ def _test_whl_and_library_deps(env):
290314
native = struct(
291315
filegroup = lambda **kwargs: filegroup_calls.append(kwargs),
292316
config_setting = lambda **_: None,
293-
glob = _glob,
317+
glob = mock_glob.glob,
294318
select = _select,
295319
),
296320
rules = struct(
297321
py_library = lambda **kwargs: py_library_calls.append(kwargs),
322+
create_inits = lambda **kwargs: ["_create_inits_target"],
298323
),
299324
)
300325

@@ -320,52 +345,50 @@ def _test_whl_and_library_deps(env):
320345
"visibility": ["//visibility:public"],
321346
},
322347
]) # buildifier: @unsorted-dict-items
323-
env.expect.that_collection(py_library_calls).contains_exactly([
324-
{
325-
"name": "pkg",
326-
"srcs": _glob(
327-
["site-packages/**/*.py"],
328-
exclude = [],
329-
allow_empty = True,
330-
),
331-
"pyi_srcs": _glob(["site-packages/**/*.pyi"], allow_empty = True),
332-
"data": [] + _glob(
333-
["site-packages/**/*"],
334-
exclude = [
335-
"**/*.py",
336-
"**/*.pyc",
337-
"**/*.pyc.*",
338-
"**/*.dist-info/RECORD",
339-
] + glob_excludes.version_dependent_exclusions(),
340-
),
341-
"imports": ["site-packages"],
342-
"deps": [
343-
"@pypi_bar_baz//:pkg",
344-
"@pypi_foo//:pkg",
345-
] + _select(
346-
{
347-
Label("//python/config_settings:is_python_3.9"): ["@pypi_py39_dep//:pkg"],
348-
"@platforms//cpu:aarch64": ["@pypi_arm_dep//:pkg"],
349-
"@platforms//os:windows": ["@pypi_win_dep//:pkg"],
350-
":is_python_3.10_linux_ppc64le": ["@pypi_py310_linux_ppc64le_dep//:pkg"],
351-
":is_python_3.9_anyos_aarch64": ["@pypi_py39_arm_dep//:pkg"],
352-
":is_python_3.9_linux_anyarch": ["@pypi_py39_linux_dep//:pkg"],
353-
":is_linux_x86_64": ["@pypi_linux_intel_dep//:pkg"],
354-
"//conditions:default": [],
355-
},
356-
),
357-
"tags": ["tag1", "tag2"],
358-
"visibility": ["//visibility:public"],
359-
"experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"),
360-
},
361-
]) # buildifier: @unsorted-dict-items
348+
349+
env.expect.that_collection(py_library_calls).has_size(1)
350+
if len(py_library_calls) != 1:
351+
return
352+
env.expect.that_dict(py_library_calls[0]).contains_exactly({
353+
"name": "pkg",
354+
"srcs": ["site-packages/foo/SRCS.py"] + _select({
355+
Label("//python/config_settings:is_venvs_site_packages"): [],
356+
"//conditions:default": ["_create_inits_target"],
357+
}),
358+
"pyi_srcs": ["site-packages/foo/PYI.pyi"],
359+
"data": ["site-packages/foo/DATA.txt"],
360+
"imports": ["site-packages"],
361+
"deps": [
362+
"@pypi_bar_baz//:pkg",
363+
"@pypi_foo//:pkg",
364+
] + _select(
365+
{
366+
Label("//python/config_settings:is_python_3.9"): ["@pypi_py39_dep//:pkg"],
367+
"@platforms//cpu:aarch64": ["@pypi_arm_dep//:pkg"],
368+
"@platforms//os:windows": ["@pypi_win_dep//:pkg"],
369+
":is_python_3.10_linux_ppc64le": ["@pypi_py310_linux_ppc64le_dep//:pkg"],
370+
":is_python_3.9_anyos_aarch64": ["@pypi_py39_arm_dep//:pkg"],
371+
":is_python_3.9_linux_anyarch": ["@pypi_py39_linux_dep//:pkg"],
372+
":is_linux_x86_64": ["@pypi_linux_intel_dep//:pkg"],
373+
"//conditions:default": [],
374+
},
375+
),
376+
"tags": ["tag1", "tag2"],
377+
"visibility": ["//visibility:public"],
378+
"experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"),
379+
}) # buildifier: @unsorted-dict-items
362380

363381
_tests.append(_test_whl_and_library_deps)
364382

365383
def _test_group(env):
366384
alias_calls = []
367385
py_library_calls = []
368386

387+
mock_glob = _mock_glob()
388+
mock_glob.results.append(["site-packages/foo/srcs.py"])
389+
mock_glob.results.append(["site-packages/foo/data.txt"])
390+
mock_glob.results.append(["site-packages/foo/pyi.pyi"])
391+
369392
whl_library_targets(
370393
name = "foo.whl",
371394
dep_template = "@pypi_{name}//:{target}",
@@ -384,52 +407,85 @@ def _test_group(env):
384407
filegroups = {},
385408
native = struct(
386409
config_setting = lambda **_: None,
387-
glob = _glob,
410+
glob = mock_glob.glob,
388411
alias = lambda **kwargs: alias_calls.append(kwargs),
389412
select = _select,
390413
),
391414
rules = struct(
392415
py_library = lambda **kwargs: py_library_calls.append(kwargs),
416+
create_inits = lambda **kwargs: ["_create_inits_target"],
393417
),
394418
)
395419

396420
env.expect.that_collection(alias_calls).contains_exactly([
397421
{"name": "pkg", "actual": "@pypi__groups//:qux_pkg", "visibility": ["//visibility:public"]},
398422
{"name": "whl", "actual": "@pypi__groups//:qux_whl", "visibility": ["//visibility:public"]},
399423
]) # buildifier: @unsorted-dict-items
400-
env.expect.that_collection(py_library_calls).contains_exactly([
401-
{
402-
"name": "_pkg",
403-
"srcs": _glob(["site-packages/**/*.py"], exclude = [], allow_empty = True),
404-
"pyi_srcs": _glob(["site-packages/**/*.pyi"], allow_empty = True),
405-
"data": [] + _glob(
406-
["site-packages/**/*"],
407-
exclude = [
408-
"**/*.py",
409-
"**/*.pyc",
410-
"**/*.pyc.*",
411-
"**/*.dist-info/RECORD",
412-
] + glob_excludes.version_dependent_exclusions(),
413-
),
414-
"imports": ["site-packages"],
415-
"deps": ["@pypi_bar_baz//:pkg"] + _select({
416-
"@platforms//os:linux": ["@pypi_box//:pkg"],
417-
":is_linux_x86_64": ["@pypi_box//:pkg", "@pypi_box_amd64//:pkg"],
418-
"//conditions:default": [],
419-
}),
420-
"tags": [],
421-
"visibility": ["@pypi__groups//:__pkg__"],
422-
"experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"),
423-
},
424-
]) # buildifier: @unsorted-dict-items
424+
425+
env.expect.that_collection(py_library_calls).has_size(1)
426+
if len(py_library_calls) != 1:
427+
return
428+
429+
py_library_call = py_library_calls[0]
430+
env.expect.where(case = "verify py library call").that_dict(
431+
py_library_call,
432+
).contains_exactly({
433+
"name": "_pkg",
434+
"srcs": ["site-packages/foo/srcs.py"] + _select({
435+
Label("//python/config_settings:is_venvs_site_packages"): [],
436+
"//conditions:default": ["_create_inits_target"],
437+
}),
438+
"pyi_srcs": ["site-packages/foo/pyi.pyi"],
439+
"data": ["site-packages/foo/data.txt"],
440+
"imports": ["site-packages"],
441+
"deps": ["@pypi_bar_baz//:pkg"] + _select({
442+
"@platforms//os:linux": ["@pypi_box//:pkg"],
443+
":is_linux_x86_64": ["@pypi_box//:pkg", "@pypi_box_amd64//:pkg"],
444+
"//conditions:default": [],
445+
}),
446+
"tags": [],
447+
"visibility": ["@pypi__groups//:__pkg__"],
448+
"experimental_venvs_site_packages": Label("//python/config_settings:venvs_site_packages"),
449+
}) # buildifier: @unsorted-dict-items
450+
451+
env.expect.that_collection(mock_glob.calls, expr = "glob calls").contains_exactly([
452+
_glob_call(["site-packages/**/*.py"], exclude = [], allow_empty = True),
453+
_glob_call(["site-packages/**/*"], exclude = [
454+
"**/*.py",
455+
"**/*.pyc",
456+
"**/*.pyc.*",
457+
"**/*.dist-info/RECORD",
458+
]),
459+
_glob_call(["site-packages/**/*.pyi"], allow_empty = True),
460+
])
425461

426462
_tests.append(_test_group)
427463

428464
def _glob(*args, **kwargs):
429-
return [struct(
465+
return [_glob_call(*args, **kwargs)]
466+
467+
def _glob_call(*args, **kwargs):
468+
return struct(
430469
glob = args,
431470
kwargs = kwargs,
432-
)]
471+
)
472+
473+
def _mock_glob():
474+
def glob(*args, **kwargs):
475+
mock.calls.append(_glob_call(*args, **kwargs))
476+
if not mock.results:
477+
fail("Mock glob missing for invocation: args={} kwargs={}".format(
478+
args,
479+
kwargs,
480+
))
481+
return mock.results.pop(0)
482+
483+
mock = struct(
484+
calls = [],
485+
results = [],
486+
glob = glob,
487+
)
488+
return mock
433489

434490
def _select(*args, **kwargs):
435491
"""We need to have this mock select because we still need to support bazel 6."""

0 commit comments

Comments
 (0)