blob: 79ffea54a171de23e167b7b98caebaa4481fedd2 [file] [log] [blame]
Ignas Anikevicius04a803c2024-06-23 09:20:18 +09001# Copyright 2023 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"common attributes for whl_library and pip_repository"
16
17ATTRS = {
18 "download_only": attr.bool(
19 doc = """
20Whether to use "pip download" instead of "pip wheel". Disables building wheels from source, but allows use of
21--platform, --python-version, --implementation, and --abi in --extra_pip_args to download wheels for a different
22platform from the host platform.
23 """,
24 ),
25 "enable_implicit_namespace_pkgs": attr.bool(
26 default = False,
27 doc = """
28If true, disables conversion of native namespace packages into pkg-util style namespace packages. When set all py_binary
29and py_test targets must specify either `legacy_create_init=False` or the global Bazel option
30`--incompatible_default_to_explicit_init_py` to prevent `__init__.py` being automatically generated in every directory.
31
32This option is required to support some packages which cannot handle the conversion to pkg-util style.
33 """,
34 ),
35 "environment": attr.string_dict(
36 doc = """
37Environment variables to set in the pip subprocess.
38Can be used to set common variables such as `http_proxy`, `https_proxy` and `no_proxy`
39Note that pip is run with "--isolated" on the CLI so `PIP_<VAR>_<NAME>`
40style env vars are ignored, but env vars that control requests and urllib3
41can be passed. If you need `PIP_<VAR>_<NAME>`, take a look at `extra_pip_args`
42and `envsubst`.
43 """,
44 default = {},
45 ),
46 "envsubst": attr.string_list(
47 mandatory = False,
48 doc = """\
49A list of environment variables to substitute (e.g. `["PIP_INDEX_URL",
50"PIP_RETRIES"]`). The corresponding variables are expanded in `extra_pip_args`
51using the syntax `$VARNAME` or `${VARNAME}` (expanding to empty string if unset)
52or `${VARNAME:-default}` (expanding to default if the variable is unset or empty
53in the environment). Note: On Bazel 6 and Bazel 7.0 changes to the variables named
54here do not cause packages to be re-fetched. Don't fetch different things based
55on the value of these variables.
56""",
57 ),
58 "experimental_requirement_cycles": attr.string_list_dict(
59 default = {},
60 doc = """\
61A mapping of dependency cycle names to a list of requirements which form that cycle.
62
63Requirements which form cycles will be installed together and taken as
64dependencies together in order to ensure that the cycle is always satisified.
65
66Example:
67 `sphinx` depends on `sphinxcontrib-serializinghtml`
68 When listing both as requirements, ala
69
70 ```
71 py_binary(
72 name = "doctool",
73 ...
74 deps = [
75 "@pypi//sphinx:pkg",
76 "@pypi//sphinxcontrib_serializinghtml",
77 ]
78 )
79 ```
80
81 Will produce a Bazel error such as
82
83 ```
84 ERROR: .../external/pypi_sphinxcontrib_serializinghtml/BUILD.bazel:44:6: in alias rule @pypi_sphinxcontrib_serializinghtml//:pkg: cycle in dependency graph:
85 //:doctool (...)
86 @pypi//sphinxcontrib_serializinghtml:pkg (...)
87 .-> @pypi_sphinxcontrib_serializinghtml//:pkg (...)
88 | @pypi_sphinxcontrib_serializinghtml//:_pkg (...)
89 | @pypi_sphinx//:pkg (...)
90 | @pypi_sphinx//:_pkg (...)
91 `-- @pypi_sphinxcontrib_serializinghtml//:pkg (...)
92 ```
93
94 Which we can resolve by configuring these two requirements to be installed together as a cycle
95
96 ```
97 pip_parse(
98 ...
99 experimental_requirement_cycles = {
100 "sphinx": [
101 "sphinx",
102 "sphinxcontrib-serializinghtml",
103 ]
104 },
105 )
106 ```
107
108Warning:
109 If a dependency participates in multiple cycles, all of those cycles must be
110 collapsed down to one. For instance `a <-> b` and `a <-> c` cannot be listed
111 as two separate cycles.
112""",
113 ),
114 "experimental_target_platforms": attr.string_list(
115 default = [],
116 doc = """\
117A list of platforms that we will generate the conditional dependency graph for
118cross platform wheels by parsing the wheel metadata. This will generate the
119correct dependencies for packages like `sphinx` or `pylint`, which include
120`colorama` when installed and used on Windows platforms.
121
122An empty list means falling back to the legacy behaviour where the host
123platform is the target platform.
124
125WARNING: It may not work as expected in cases where the python interpreter
126implementation that is being used at runtime is different between different platforms.
127This has been tested for CPython only.
128
129For specific target platforms use values of the form `<os>_<arch>` where `<os>`
130is one of `linux`, `osx`, `windows` and arch is one of `x86_64`, `x86_32`,
131`aarch64`, `s390x` and `ppc64le`.
132
133You can also target a specific Python version by using `cp3<minor_version>_<os>_<arch>`.
134If multiple python versions are specified as target platforms, then select statements
135of the `lib` and `whl` targets will include usage of version aware toolchain config
136settings like `@rules_python//python/config_settings:is_python_3.y`.
137
138Special values: `host` (for generating deps for the host platform only) and
139`<prefix>_*` values. For example, `cp39_*`, `linux_*`, `cp39_linux_*`.
140
141NOTE: this is not for cross-compiling Python wheels but rather for parsing the `whl` METADATA correctly.
142""",
143 ),
144 "extra_pip_args": attr.string_list(
145 doc = """Extra arguments to pass on to pip. Must not contain spaces.
146
147Supports environment variables using the syntax `$VARNAME` or
148`${VARNAME}` (expanding to empty string if unset) or
149`${VARNAME:-default}` (expanding to default if the variable is unset
150or empty in the environment), if `"VARNAME"` is listed in the
151`envsubst` attribute. See also `envsubst`.
152""",
153 ),
154 "isolated": attr.bool(
155 doc = """\
156Whether or not to pass the [--isolated](https://pip.pypa.io/en/stable/cli/pip/#cmdoption-isolated) flag to
157the underlying pip command. Alternatively, the `RULES_PYTHON_PIP_ISOLATED` environment variable can be used
158to control this flag.
159""",
160 default = True,
161 ),
162 "pip_data_exclude": attr.string_list(
163 doc = "Additional data exclusion parameters to add to the pip packages BUILD file.",
164 ),
165 "python_interpreter": attr.string(
166 doc = """\
167The python interpreter to use. This can either be an absolute path or the name
168of a binary found on the host's `PATH` environment variable. If no value is set
169`python3` is defaulted for Unix systems and `python.exe` for Windows.
170""",
171 # NOTE: This attribute should not have a default. See `_get_python_interpreter_attr`
172 # default = "python3"
173 ),
174 "python_interpreter_target": attr.label(
175 allow_single_file = True,
176 doc = """
177If you are using a custom python interpreter built by another repository rule,
178use this attribute to specify its BUILD target. This allows pip_repository to invoke
179pip using the same interpreter as your toolchain. If set, takes precedence over
180python_interpreter. An example value: "@python3_x86_64-unknown-linux-gnu//:python".
181""",
182 ),
183 "quiet": attr.bool(
184 default = True,
185 doc = """\
186If True, suppress printing stdout and stderr output to the terminal.
187
188If you would like to get more diagnostic output, please use:
189
190 RULES_PYTHON_REPO_DEBUG=1
191
192or
193
194 RULES_PYTHON_REPO_DEBUG_VERBOSITY=<INFO|DEBUG|TRACE>
195""",
196 ),
197 # 600 is documented as default here: https://docs.bazel.build/versions/master/skylark/lib/repository_ctx.html#execute
198 "timeout": attr.int(
199 default = 600,
200 doc = "Timeout (in seconds) on the rule's execution duration.",
201 ),
202}
203
204def use_isolated(ctx, attr):
205 """Determine whether or not to pass the pip `--isolated` flag to the pip invocation.
206
207 Args:
208 ctx: repository or module context
209 attr: attributes for the repo rule or tag extension
210
211 Returns:
212 True if --isolated should be passed
213 """
214 use_isolated = attr.isolated
215
216 # The environment variable will take precedence over the attribute
217 isolated_env = ctx.os.environ.get("RULES_PYTHON_PIP_ISOLATED", None)
218 if isolated_env != None:
219 if isolated_env.lower() in ("0", "false"):
220 use_isolated = False
221 else:
222 use_isolated = True
223
224 return use_isolated