Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions news/sourceless-wheel-srcs.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(pypi) Fixed analysis failures for source-less wheels with dependencies in
per-wheel repositories.
37 changes: 29 additions & 8 deletions python/private/pypi/whl_library_targets.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def whl_library_targets(
**kwargs: Extra args passed to the {obj}`whl_library_deps_targets` and {obj}`whl_library_srcs`.
"""
create_extra_targets = bool(requires_dist or group_name) and dep_template
whl_library_srcs(
wrapper_srcs = whl_library_srcs(
name = name,
sdist_filename = sdist_filename,
data_exclude = data_exclude,
Expand Down Expand Up @@ -133,6 +133,7 @@ def whl_library_targets(
dep_template = dep_template, # only needed if requires_dist is present
repo = None, # set aliases in the same repo
aliases = {},
srcs = wrapper_srcs,
**kwargs
)

Expand Down Expand Up @@ -193,9 +194,14 @@ def whl_library_srcs(
pkg_name: {type}`str` The label name to use for the py_library target.
native: {type}`native` The native struct for overriding in tests.
rules: {type}`struct` A struct with references to rules for creating targets.

Returns:
The source labels attached to the generated `py_library`, or `None` when
`rules` does not define `py_library`.
"""
tags = sorted(tags)
data = [] + data
wrapper_srcs = None

bins_for_data_label = []

Expand Down Expand Up @@ -301,6 +307,7 @@ def whl_library_srcs(
# pure-Python code, e.g. pymssql, which is written in Cython.
allow_empty = True,
)
wrapper_srcs = [pkg_name] if srcs else []

# NOTE: pyi files should probably be excluded because they're carried
# by the pyi_srcs attribute. However, historical behavior included
Expand Down Expand Up @@ -328,13 +335,19 @@ def whl_library_srcs(
)

if not enable_implicit_namespace_pkgs:
generated_namespace_package_files = rules.create_inits(
srcs = srcs + data + pyi_srcs,
ignored_dirnames = [], # If you need to ignore certain folders, you can patch rules_python here to do so.
root = "site-packages",
)
if not wrapper_srcs and generated_namespace_package_files:
wrapper_srcs = select({
_IS_VENV_SITE_PACKAGES_YES: [],
"//conditions:default": [pkg_name],
})
generated_namespace_package_files = select({
_IS_VENV_SITE_PACKAGES_YES: [],
"//conditions:default": rules.create_inits(
srcs = srcs + data + pyi_srcs,
ignored_dirnames = [], # If you need to ignore certain folders, you can patch rules_python here to do so.
root = "site-packages",
),
"//conditions:default": generated_namespace_package_files,
})
namespace_package_files += generated_namespace_package_files
srcs = srcs + generated_namespace_package_files
Expand All @@ -356,6 +369,7 @@ def whl_library_srcs(
experimental_venvs_site_packages = _VENV_SITE_PACKAGES_FLAG,
namespace_package_files = namespace_package_files,
)
return wrapper_srcs

def whl_library_deps_targets(
*,
Expand All @@ -369,6 +383,7 @@ def whl_library_deps_targets(
group_deps = [],
group_name = None,
dep_template,
srcs = None,
tags = [],
visibility = ["//visibility:public"],
native = native,
Expand Down Expand Up @@ -396,6 +411,9 @@ def whl_library_deps_targets(
include: {type}`list[str]` The list of packages to include.
group_name: {type}`str | None` name of the dependency group (if any).
dep_template: {type}`str | None` The dep_template to use.
srcs: {type}`list[Label] | None` or a configurable expression with the
source labels attached to the wrapper `py_library`. If `None`, the
source library target is used.
tags: {type}`list[str]` The tags set on the targets.
repo: {type}`str | Label | None` The BUILD.bazel label to the parent repo that has the
sources. If none, then will take the targets from the current dir.
Expand Down Expand Up @@ -501,10 +519,13 @@ def whl_library_deps_targets(
)

if hasattr(rules, "py_library"):
if srcs == None:
srcs = [repo_label(PY_SRCS_LABEL)]
rules.py_library(
name = py_library_label,
# We include as srcs to ensure that the (locations :pkg) works as expected.
srcs = [repo_label(PY_SRCS_LABEL)],
# Forward source-producing targets through `srcs` so downstream
# `$(locations :pkg)` expansion does not reject source-less wheels.
srcs = srcs,
deps = _deps(
# We include as deps, so that `PyInfo` and friends (e.g. `pyi_srcs`) get
# propagated. Just passing the target as `srcs` is not enough to propagate
Expand Down
116 changes: 116 additions & 0 deletions tests/pypi/whl_library_targets/whl_library_targets_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,46 @@ load(
"//python/private/pypi:whl_library_targets.bzl",
"whl_library_deps_targets",
"whl_library_srcs",
"whl_library_targets",
) # buildifier: disable=bzl-visibility
load("//tests/support/mocks:mocks.bzl", "mocks")

_tests = []

def _make_whl_library_targets_py_library_calls(
*,
srcs,
data,
generated_inits,
enable_implicit_namespace_pkgs = False):
py_library_calls = []
m_glob = mocks.glob()
m_glob.results.append([]) # bin
m_glob.results.append([]) # rewrite-bin
m_glob.results.append([]) # rewrite-record
m_glob.results.append(srcs)
m_glob.results.append(data)
m_glob.results.append([]) # pyi

whl_library_targets(
name = "foo-0-py3-none-any.whl",
metadata_name = "Foo",
requires_dist = ["bar"],
dep_template = "@pypi//{name}:{target}",
enable_implicit_namespace_pkgs = enable_implicit_namespace_pkgs,
filegroups = {},
native = struct(glob = m_glob.glob),
rules = struct(
create_inits = lambda **_: generated_inits,
env_marker_setting = lambda **_: None,
gen_wheel_record = lambda **_: None,
py_library = lambda **kwargs: py_library_calls.append(kwargs),
venv_rewrite_shebang = lambda **_: None,
),
)

return py_library_calls

def _test_filegroups(env):
calls = []

Expand Down Expand Up @@ -191,6 +226,87 @@ def _test_whl_library_deps_targets(env):

_tests.append(_test_whl_library_deps_targets)

def _test_whl_library_targets_sourceless(env):
for enable_implicit_namespace_pkgs, expected_leaf_srcs in [
(False, [] + select({
Label("//python/config_settings:_is_venvs_site_packages_yes"): [],
"//conditions:default": [],
})),
(True, []),
]:
py_library_calls = _make_whl_library_targets_py_library_calls(
srcs = [],
data = [],
generated_inits = [],
enable_implicit_namespace_pkgs = enable_implicit_namespace_pkgs,
)

env.expect.that_collection(py_library_calls).has_size(2)
if len(py_library_calls) != 2:
return

env.expect.that_dict(py_library_calls[0]).contains_at_least({
"srcs": expected_leaf_srcs,
})
env.expect.that_dict(py_library_calls[1]).contains_exactly({
"name": "pkg",
"srcs": [],
"deps": ["srcs", "@pypi//bar:pkg"],
"tags": [],
"visibility": ["//visibility:public"],
}) # buildifier: @unsorted-dict-items

_tests.append(_test_whl_library_targets_sourceless)

def _test_whl_library_targets_sourceful(env):
for srcs, data, generated_inits, expected_leaf_srcs, expected_wrapper_srcs in [
(
["site-packages/foo.py"],
[],
[],
["site-packages/foo.py"] + select({
Label("//python/config_settings:_is_venvs_site_packages_yes"): [],
"//conditions:default": [],
}),
["srcs"],
),
(
[],
["site-packages/ext/mod.so"],
["site-packages/ext/__init__.py"],
[] + select({
Label("//python/config_settings:_is_venvs_site_packages_yes"): [],
"//conditions:default": ["site-packages/ext/__init__.py"],
}),
select({
Label("//python/config_settings:_is_venvs_site_packages_yes"): [],
"//conditions:default": ["srcs"],
}),
),
]:
py_library_calls = _make_whl_library_targets_py_library_calls(
srcs = srcs,
data = data,
generated_inits = generated_inits,
)

env.expect.that_collection(py_library_calls).has_size(2)
if len(py_library_calls) != 2:
return

env.expect.that_dict(py_library_calls[0]).contains_at_least({
"srcs": expected_leaf_srcs,
})
env.expect.that_dict(py_library_calls[1]).contains_exactly({
"name": "pkg",
"srcs": expected_wrapper_srcs,
"deps": ["srcs", "@pypi//bar:pkg"],
"tags": [],
"visibility": ["//visibility:public"],
}) # buildifier: @unsorted-dict-items

_tests.append(_test_whl_library_targets_sourceful)

def _test_whl_library_deps_targets_no_deps(env):
alias_calls = []
filegroup_calls = []
Expand Down