Ignas Anikevicius | 04a803c | 2024-06-23 09:20:18 +0900 | [diff] [blame^] | 1 | # 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 | |
| 17 | ATTRS = { |
| 18 | "download_only": attr.bool( |
| 19 | doc = """ |
| 20 | Whether 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 |
| 22 | platform from the host platform. |
| 23 | """, |
| 24 | ), |
| 25 | "enable_implicit_namespace_pkgs": attr.bool( |
| 26 | default = False, |
| 27 | doc = """ |
| 28 | If true, disables conversion of native namespace packages into pkg-util style namespace packages. When set all py_binary |
| 29 | and 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 | |
| 32 | This 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 = """ |
| 37 | Environment variables to set in the pip subprocess. |
| 38 | Can be used to set common variables such as `http_proxy`, `https_proxy` and `no_proxy` |
| 39 | Note that pip is run with "--isolated" on the CLI so `PIP_<VAR>_<NAME>` |
| 40 | style env vars are ignored, but env vars that control requests and urllib3 |
| 41 | can be passed. If you need `PIP_<VAR>_<NAME>`, take a look at `extra_pip_args` |
| 42 | and `envsubst`. |
| 43 | """, |
| 44 | default = {}, |
| 45 | ), |
| 46 | "envsubst": attr.string_list( |
| 47 | mandatory = False, |
| 48 | doc = """\ |
| 49 | A list of environment variables to substitute (e.g. `["PIP_INDEX_URL", |
| 50 | "PIP_RETRIES"]`). The corresponding variables are expanded in `extra_pip_args` |
| 51 | using the syntax `$VARNAME` or `${VARNAME}` (expanding to empty string if unset) |
| 52 | or `${VARNAME:-default}` (expanding to default if the variable is unset or empty |
| 53 | in the environment). Note: On Bazel 6 and Bazel 7.0 changes to the variables named |
| 54 | here do not cause packages to be re-fetched. Don't fetch different things based |
| 55 | on the value of these variables. |
| 56 | """, |
| 57 | ), |
| 58 | "experimental_requirement_cycles": attr.string_list_dict( |
| 59 | default = {}, |
| 60 | doc = """\ |
| 61 | A mapping of dependency cycle names to a list of requirements which form that cycle. |
| 62 | |
| 63 | Requirements which form cycles will be installed together and taken as |
| 64 | dependencies together in order to ensure that the cycle is always satisified. |
| 65 | |
| 66 | Example: |
| 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 | |
| 108 | Warning: |
| 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 = """\ |
| 117 | A list of platforms that we will generate the conditional dependency graph for |
| 118 | cross platform wheels by parsing the wheel metadata. This will generate the |
| 119 | correct dependencies for packages like `sphinx` or `pylint`, which include |
| 120 | `colorama` when installed and used on Windows platforms. |
| 121 | |
| 122 | An empty list means falling back to the legacy behaviour where the host |
| 123 | platform is the target platform. |
| 124 | |
| 125 | WARNING: It may not work as expected in cases where the python interpreter |
| 126 | implementation that is being used at runtime is different between different platforms. |
| 127 | This has been tested for CPython only. |
| 128 | |
| 129 | For specific target platforms use values of the form `<os>_<arch>` where `<os>` |
| 130 | is one of `linux`, `osx`, `windows` and arch is one of `x86_64`, `x86_32`, |
| 131 | `aarch64`, `s390x` and `ppc64le`. |
| 132 | |
| 133 | You can also target a specific Python version by using `cp3<minor_version>_<os>_<arch>`. |
| 134 | If multiple python versions are specified as target platforms, then select statements |
| 135 | of the `lib` and `whl` targets will include usage of version aware toolchain config |
| 136 | settings like `@rules_python//python/config_settings:is_python_3.y`. |
| 137 | |
| 138 | Special values: `host` (for generating deps for the host platform only) and |
| 139 | `<prefix>_*` values. For example, `cp39_*`, `linux_*`, `cp39_linux_*`. |
| 140 | |
| 141 | NOTE: 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 | |
| 147 | Supports 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 |
| 150 | or empty in the environment), if `"VARNAME"` is listed in the |
| 151 | `envsubst` attribute. See also `envsubst`. |
| 152 | """, |
| 153 | ), |
| 154 | "isolated": attr.bool( |
| 155 | doc = """\ |
| 156 | Whether or not to pass the [--isolated](https://pip.pypa.io/en/stable/cli/pip/#cmdoption-isolated) flag to |
| 157 | the underlying pip command. Alternatively, the `RULES_PYTHON_PIP_ISOLATED` environment variable can be used |
| 158 | to 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 = """\ |
| 167 | The python interpreter to use. This can either be an absolute path or the name |
| 168 | of 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 = """ |
| 177 | If you are using a custom python interpreter built by another repository rule, |
| 178 | use this attribute to specify its BUILD target. This allows pip_repository to invoke |
| 179 | pip using the same interpreter as your toolchain. If set, takes precedence over |
| 180 | python_interpreter. An example value: "@python3_x86_64-unknown-linux-gnu//:python". |
| 181 | """, |
| 182 | ), |
| 183 | "quiet": attr.bool( |
| 184 | default = True, |
| 185 | doc = """\ |
| 186 | If True, suppress printing stdout and stderr output to the terminal. |
| 187 | |
| 188 | If you would like to get more diagnostic output, please use: |
| 189 | |
| 190 | RULES_PYTHON_REPO_DEBUG=1 |
| 191 | |
| 192 | or |
| 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 | |
| 204 | def 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 |