aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgnas Anikevicius <ignas.anikevicius@woven-planet.global>2023-07-20 11:27:36 +0900
committerGitHub <noreply@github.com>2023-07-20 02:27:36 +0000
commit5c5ab5bd9577a284784d1c8b27bf58336de06010 (patch)
tree85101abed37397f7fd869e3f63dc122b494692f6
parent5c37fa7f7a132432648b4e7970a0aa47c173f0fc (diff)
downloadbazelbuild-rules_python-5c5ab5bd9577a284784d1c8b27bf58336de06010.tar.gz
fix(multi-versions): correctly default 'main' arg for transition rules (#1316)
This fixes a bug where the version-aware rules required `main` to always be explicitly specified. This was necessary because the main file is named after the outer target (e.g. "foo"), but usage of the main file is done by the inner target ("_foo"). The net effect is the inner target looks for "_foo.py", while only "foo.py" is in srcs. To fix, the wrappers set main, if it isn't already set, to their name + ".py" Work towards #1262
-rw-r--r--examples/multi_python_versions/tests/BUILD.bazel23
-rw-r--r--python/config_settings/private/BUILD.bazel0
-rw-r--r--python/config_settings/private/py_args.bzl42
-rw-r--r--python/config_settings/transition.bzl14
-rw-r--r--tests/config_settings/transition/BUILD.bazel3
-rw-r--r--tests/config_settings/transition/py_args_tests.bzl68
6 files changed, 141 insertions, 9 deletions
diff --git a/examples/multi_python_versions/tests/BUILD.bazel b/examples/multi_python_versions/tests/BUILD.bazel
index 2292d53..5df41bd 100644
--- a/examples/multi_python_versions/tests/BUILD.bazel
+++ b/examples/multi_python_versions/tests/BUILD.bazel
@@ -1,13 +1,22 @@
+load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
load("@python//3.10:defs.bzl", py_binary_3_10 = "py_binary", py_test_3_10 = "py_test")
load("@python//3.11:defs.bzl", py_binary_3_11 = "py_binary", py_test_3_11 = "py_test")
load("@python//3.8:defs.bzl", py_binary_3_8 = "py_binary", py_test_3_8 = "py_test")
load("@python//3.9:defs.bzl", py_binary_3_9 = "py_binary", py_test_3_9 = "py_test")
load("@rules_python//python:defs.bzl", "py_binary", "py_test")
+copy_file(
+ name = "copy_version",
+ src = "version.py",
+ out = "version_default.py",
+ is_executable = True,
+)
+
+# NOTE: We are testing that the `main` is an optional param as per official
+# docs https://bazel.build/reference/be/python#py_binary.main
py_binary(
name = "version_default",
- srcs = ["version.py"],
- main = "version.py",
+ srcs = ["version_default.py"],
)
py_binary_3_8(
@@ -69,11 +78,17 @@ py_test_3_11(
deps = ["//libs/my_lib"],
)
+copy_file(
+ name = "copy_version_test",
+ src = "version_test.py",
+ out = "version_default_test.py",
+ is_executable = True,
+)
+
py_test(
name = "version_default_test",
- srcs = ["version_test.py"],
+ srcs = ["version_default_test.py"],
env = {"VERSION_CHECK": "3.9"}, # The default defined in the WORKSPACE.
- main = "version_test.py",
)
py_test_3_8(
diff --git a/python/config_settings/private/BUILD.bazel b/python/config_settings/private/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/config_settings/private/BUILD.bazel
diff --git a/python/config_settings/private/py_args.bzl b/python/config_settings/private/py_args.bzl
new file mode 100644
index 0000000..09a2646
--- /dev/null
+++ b/python/config_settings/private/py_args.bzl
@@ -0,0 +1,42 @@
+# Copyright 2023 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""A helper to extract default args for the transition rule."""
+
+def py_args(name, kwargs):
+ """A helper to extract common py_binary and py_test args
+
+ See https://bazel.build/reference/be/python#py_binary and
+ https://bazel.build/reference/be/python#py_test for the list
+ that should be returned
+
+ Args:
+ name: The name of the target.
+ kwargs: The kwargs to be extracted from; MODIFIED IN-PLACE.
+
+ Returns:
+ A dict with the extracted arguments
+ """
+ return dict(
+ args = kwargs.pop("args", None),
+ data = kwargs.pop("data", None),
+ env = kwargs.pop("env", None),
+ srcs = kwargs.pop("srcs", None),
+ deps = kwargs.pop("deps", None),
+ # See https://bazel.build/reference/be/python#py_binary.main
+ # for default logic.
+ # NOTE: This doesn't match the exact way a regular py_binary searches for
+ # it's main amongst the srcs, but is close enough for most cases.
+ main = kwargs.pop("main", name + ".py"),
+ )
diff --git a/python/config_settings/transition.bzl b/python/config_settings/transition.bzl
index 0a3d51c..20e03dc 100644
--- a/python/config_settings/transition.bzl
+++ b/python/config_settings/transition.bzl
@@ -18,6 +18,7 @@ them to the desired target platform.
load("@bazel_skylib//lib:dicts.bzl", "dicts")
load("//python:defs.bzl", _py_binary = "py_binary", _py_test = "py_test")
+load("//python/config_settings/private:py_args.bzl", "py_args")
def _transition_python_version_impl(_, attr):
return {"//python/config_settings:python_version": str(attr.python_version)}
@@ -138,11 +139,13 @@ _transition_py_test = rule(
)
def _py_rule(rule_impl, transition_rule, name, python_version, **kwargs):
- args = kwargs.pop("args", None)
- data = kwargs.pop("data", None)
- env = kwargs.pop("env", None)
- srcs = kwargs.pop("srcs", None)
- deps = kwargs.pop("deps", None)
+ pyargs = py_args(name, kwargs)
+ args = pyargs["args"]
+ data = pyargs["data"]
+ env = pyargs["env"]
+ srcs = pyargs["srcs"]
+ deps = pyargs["deps"]
+ main = pyargs["main"]
# Attributes common to all build rules.
# https://bazel.build/reference/be/common-definitions#common-attributes
@@ -197,6 +200,7 @@ def _py_rule(rule_impl, transition_rule, name, python_version, **kwargs):
deps = deps,
env = env,
srcs = srcs,
+ main = main,
tags = ["manual"] + (tags if tags else []),
visibility = ["//visibility:private"],
**dicts.add(common_attrs, kwargs)
diff --git a/tests/config_settings/transition/BUILD.bazel b/tests/config_settings/transition/BUILD.bazel
new file mode 100644
index 0000000..21fa50e
--- /dev/null
+++ b/tests/config_settings/transition/BUILD.bazel
@@ -0,0 +1,3 @@
+load(":py_args_tests.bzl", "py_args_test_suite")
+
+py_args_test_suite(name = "py_args_tests")
diff --git a/tests/config_settings/transition/py_args_tests.bzl b/tests/config_settings/transition/py_args_tests.bzl
new file mode 100644
index 0000000..4538c88
--- /dev/null
+++ b/tests/config_settings/transition/py_args_tests.bzl
@@ -0,0 +1,68 @@
+# Copyright 2023 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+""
+
+load("@rules_testing//lib:test_suite.bzl", "test_suite")
+load("//python/config_settings/private:py_args.bzl", "py_args") # buildifier: disable=bzl-visibility
+
+_tests = []
+
+def _test_py_args_default(env):
+ actual = py_args("foo", {})
+
+ want = {
+ "args": None,
+ "data": None,
+ "deps": None,
+ "env": None,
+ "main": "foo.py",
+ "srcs": None,
+ }
+ env.expect.that_dict(actual).contains_exactly(want)
+
+_tests.append(_test_py_args_default)
+
+def _test_kwargs_get_consumed(env):
+ kwargs = {
+ "args": ["some", "args"],
+ "data": ["data"],
+ "deps": ["deps"],
+ "env": {"key": "value"},
+ "main": "__main__.py",
+ "srcs": ["__main__.py"],
+ "visibility": ["//visibility:public"],
+ }
+ actual = py_args("bar_bin", kwargs)
+
+ want = {
+ "args": ["some", "args"],
+ "data": ["data"],
+ "deps": ["deps"],
+ "env": {"key": "value"},
+ "main": "__main__.py",
+ "srcs": ["__main__.py"],
+ }
+ env.expect.that_dict(actual).contains_exactly(want)
+ env.expect.that_dict(kwargs).keys().contains_exactly(["visibility"])
+
+_tests.append(_test_kwargs_get_consumed)
+
+def py_args_test_suite(name):
+ """Create the test suite.
+
+ Args:
+ name: the name of the test suite
+ """
+ test_suite(name = name, basic_tests = _tests)