@@ -19,250 +19,27 @@ symbols should not be used and they are either undocumented here or marked as
19
19
for internal use only.
20
20
"""
21
21
22
- load ("//python/pip_install:requirements.bzl" , _compile_pip_requirements = "compile_pip_requirements" )
23
- load ("//python/private:bzlmod_enabled.bzl" , "BZLMOD_ENABLED" )
24
- load ("//python/private:full_version.bzl" , "full_version" )
25
22
load ("//python/private:normalize_name.bzl" , "normalize_name" )
23
+ load ("//python/private/pypi:multi_pip_parse.bzl" , _multi_pip_parse = "multi_pip_parse" )
26
24
load ("//python/private/pypi:package_annotation.bzl" , _package_annotation = "package_annotation" )
25
+ load ("//python/private/pypi:pip_compile.bzl" , "pip_compile" )
27
26
load ("//python/private/pypi:pip_repository.bzl" , "pip_repository" )
28
- load ("//python/private/pypi:render_pkg_aliases .bzl" , "NO_MATCH_ERROR_MESSAGE_TEMPLATE " )
27
+ load ("//python/private/pypi:whl_library_alias .bzl" , _whl_library_alias = "whl_library_alias " )
29
28
load ("//python/private/whl_filegroup:whl_filegroup.bzl" , _whl_filegroup = "whl_filegroup" )
30
29
31
- compile_pip_requirements = _compile_pip_requirements
30
+ compile_pip_requirements = pip_compile
32
31
package_annotation = _package_annotation
33
32
pip_parse = pip_repository
34
33
whl_filegroup = _whl_filegroup
35
34
36
- def _multi_pip_parse_impl (rctx ):
37
- rules_python = rctx .attr ._rules_python_workspace .workspace_name
38
- load_statements = []
39
- install_deps_calls = []
40
- process_requirements_calls = []
41
- for python_version , pypi_repository in rctx .attr .pip_parses .items ():
42
- sanitized_python_version = python_version .replace ("." , "_" )
43
- load_statement = """\
44
- load(
45
- "@{pypi_repository}//:requirements.bzl",
46
- _{sanitized_python_version}_install_deps = "install_deps",
47
- _{sanitized_python_version}_all_requirements = "all_requirements",
48
- )""" .format (
49
- pypi_repository = pypi_repository ,
50
- sanitized_python_version = sanitized_python_version ,
51
- )
52
- load_statements .append (load_statement )
53
- process_requirements_call = """\
54
- _process_requirements(
55
- pkg_labels = _{sanitized_python_version}_all_requirements,
56
- python_version = "{python_version}",
57
- repo_prefix = "{pypi_repository}_",
58
- )""" .format (
59
- pypi_repository = pypi_repository ,
60
- python_version = python_version ,
61
- sanitized_python_version = sanitized_python_version ,
62
- )
63
- process_requirements_calls .append (process_requirements_call )
64
- install_deps_call = """ _{sanitized_python_version}_install_deps(**whl_library_kwargs)""" .format (
65
- sanitized_python_version = sanitized_python_version ,
66
- )
67
- install_deps_calls .append (install_deps_call )
68
-
69
- # NOTE @aignas 2023-10-31: I am not sure it is possible to render aliases
70
- # for all of the packages using the `render_pkg_aliases` function because
71
- # we need to know what the list of packages for each version is and then
72
- # we would be creating directories for each.
73
- macro_tmpl = "@%s_{}//:{}" % rctx .attr .name
74
-
75
- requirements_bzl = """\
76
- # Generated by python/pip.bzl
77
-
78
- load("@{rules_python}//python:pip.bzl", "whl_library_alias", "pip_utils")
79
- {load_statements}
80
-
81
- _wheel_names = []
82
- _version_map = dict()
83
- def _process_requirements(pkg_labels, python_version, repo_prefix):
84
- for pkg_label in pkg_labels:
85
- wheel_name = Label(pkg_label).package
86
- if not wheel_name:
87
- # We are dealing with the cases where we don't have aliases.
88
- workspace_name = Label(pkg_label).workspace_name
89
- wheel_name = workspace_name[len(repo_prefix):]
90
-
91
- _wheel_names.append(wheel_name)
92
- if not wheel_name in _version_map:
93
- _version_map[wheel_name] = dict()
94
- _version_map[wheel_name][python_version] = repo_prefix
95
-
96
- {process_requirements_calls}
97
-
98
- def requirement(name):
99
- return "{macro_tmpl}".format(pip_utils.normalize_name(name), "pkg")
100
-
101
- def whl_requirement(name):
102
- return "{macro_tmpl}".format(pip_utils.normalize_name(name), "whl")
103
-
104
- def data_requirement(name):
105
- return "{macro_tmpl}".format(pip_utils.normalize_name(name), "data")
106
-
107
- def dist_info_requirement(name):
108
- return "{macro_tmpl}".format(pip_utils.normalize_name(name), "dist_info")
109
-
110
- def install_deps(**whl_library_kwargs):
111
- {install_deps_calls}
112
- for wheel_name in _wheel_names:
113
- whl_library_alias(
114
- name = "{name}_" + wheel_name,
115
- wheel_name = wheel_name,
116
- default_version = "{default_version}",
117
- version_map = _version_map[wheel_name],
118
- )
119
- """ .format (
120
- name = rctx .attr .name ,
121
- install_deps_calls = "\n " .join (install_deps_calls ),
122
- load_statements = "\n " .join (load_statements ),
123
- macro_tmpl = macro_tmpl ,
124
- process_requirements_calls = "\n " .join (process_requirements_calls ),
125
- rules_python = rules_python ,
126
- default_version = rctx .attr .default_version ,
127
- )
128
- rctx .file ("requirements.bzl" , requirements_bzl )
129
- rctx .file ("BUILD.bazel" , "exports_files(['requirements.bzl'])" )
130
-
131
- _multi_pip_parse = repository_rule (
132
- _multi_pip_parse_impl ,
133
- attrs = {
134
- "default_version" : attr .string (),
135
- "pip_parses" : attr .string_dict (),
136
- "_rules_python_workspace" : attr .label (default = Label ("//:WORKSPACE" )),
137
- },
138
- )
139
-
140
- def _whl_library_alias_impl (rctx ):
141
- rules_python = rctx .attr ._rules_python_workspace .workspace_name
142
- if rctx .attr .default_version :
143
- default_repo_prefix = rctx .attr .version_map [rctx .attr .default_version ]
144
- else :
145
- default_repo_prefix = None
146
- version_map = rctx .attr .version_map .items ()
147
- build_content = ["# Generated by python/pip.bzl" ]
148
- for alias_name in ["pkg" , "whl" , "data" , "dist_info" ]:
149
- build_content .append (_whl_library_render_alias_target (
150
- alias_name = alias_name ,
151
- default_repo_prefix = default_repo_prefix ,
152
- rules_python = rules_python ,
153
- version_map = version_map ,
154
- wheel_name = rctx .attr .wheel_name ,
155
- ))
156
- rctx .file ("BUILD.bazel" , "\n " .join (build_content ))
157
-
158
- def _whl_library_render_alias_target (
159
- alias_name ,
160
- default_repo_prefix ,
161
- rules_python ,
162
- version_map ,
163
- wheel_name ):
164
- # The template below adds one @, but under bzlmod, the name
165
- # is canonical, so we have to add a second @.
166
- if BZLMOD_ENABLED :
167
- rules_python = "@" + rules_python
168
-
169
- alias = ["""\
170
- alias(
171
- name = "{alias_name}",
172
- actual = select({{""" .format (alias_name = alias_name )]
173
- for [python_version , repo_prefix ] in version_map :
174
- alias .append ("""\
175
- "@{rules_python}//python/config_settings:is_python_{full_python_version}": "{actual}",""" .format (
176
- full_python_version = full_version (python_version ),
177
- actual = "@{repo_prefix}{wheel_name}//:{alias_name}" .format (
178
- repo_prefix = repo_prefix ,
179
- wheel_name = wheel_name ,
180
- alias_name = alias_name ,
181
- ),
182
- rules_python = rules_python ,
183
- ))
184
- if default_repo_prefix :
185
- default_actual = "@{repo_prefix}{wheel_name}//:{alias_name}" .format (
186
- repo_prefix = default_repo_prefix ,
187
- wheel_name = wheel_name ,
188
- alias_name = alias_name ,
189
- )
190
- alias .append (' "//conditions:default": "{default_actual}",' .format (
191
- default_actual = default_actual ,
192
- ))
193
-
194
- alias .append (" }," ) # Close select expression condition dict
195
- if not default_repo_prefix :
196
- supported_versions = sorted ([python_version for python_version , _ in version_map ])
197
- alias .append (' no_match_error="""{}""",' .format (
198
- NO_MATCH_ERROR_MESSAGE_TEMPLATE .format (
199
- supported_versions = ", " .join (supported_versions ),
200
- rules_python = rules_python ,
201
- ),
202
- ))
203
- alias .append (" )," ) # Close the select expression
204
- alias .append (' visibility = ["//visibility:public"],' )
205
- alias .append (")" ) # Close the alias() expression
206
- return "\n " .join (alias )
207
-
208
- whl_library_alias = repository_rule (
209
- _whl_library_alias_impl ,
210
- attrs = {
211
- "default_version" : attr .string (
212
- mandatory = False ,
213
- doc = "Optional Python version in major.minor format, e.g. '3.10'." +
214
- "The Python version of the wheel to use when the versions " +
215
- "from `version_map` don't match. This allows the default " +
216
- "(version unaware) rules to match and select a wheel. If " +
217
- "not specified, then the default rules won't be able to " +
218
- "resolve a wheel and an error will occur." ,
219
- ),
220
- "version_map" : attr .string_dict (mandatory = True ),
221
- "wheel_name" : attr .string (mandatory = True ),
222
- "_rules_python_workspace" : attr .label (default = Label ("//:WORKSPACE" )),
223
- },
224
- )
225
-
226
- def multi_pip_parse (name , default_version , python_versions , python_interpreter_target , requirements_lock , ** kwargs ):
227
- """NOT INTENDED FOR DIRECT USE!
228
-
229
- This is intended to be used by the multi_pip_parse implementation in the template of the
230
- multi_toolchain_aliases repository rule.
231
-
232
- Args:
233
- name: the name of the multi_pip_parse repository.
234
- default_version: the default Python version.
235
- python_versions: all Python toolchain versions currently registered.
236
- python_interpreter_target: a dictionary which keys are Python versions and values are resolved host interpreters.
237
- requirements_lock: a dictionary which keys are Python versions and values are locked requirements files.
238
- **kwargs: extra arguments passed to all wrapped pip_parse.
239
-
240
- Returns:
241
- The internal implementation of multi_pip_parse repository rule.
242
- """
243
- pip_parses = {}
244
- for python_version in python_versions :
245
- if not python_version in python_interpreter_target :
246
- fail ("Missing python_interpreter_target for Python version %s in '%s'" % (python_version , name ))
247
- if not python_version in requirements_lock :
248
- fail ("Missing requirements_lock for Python version %s in '%s'" % (python_version , name ))
249
-
250
- pip_parse_name = name + "_" + python_version .replace ("." , "_" )
251
- pip_parse (
252
- name = pip_parse_name ,
253
- python_interpreter_target = python_interpreter_target [python_version ],
254
- requirements_lock = requirements_lock [python_version ],
255
- ** kwargs
256
- )
257
- pip_parses [python_version ] = pip_parse_name
258
-
259
- return _multi_pip_parse (
260
- name = name ,
261
- default_version = default_version ,
262
- pip_parses = pip_parses ,
263
- )
264
-
265
35
# Extra utilities visible to rules_python users.
266
36
pip_utils = struct (
267
37
normalize_name = normalize_name ,
268
38
)
39
+
40
+ # The following are only exported here because they are used from
41
+ # multi_toolchain_aliases repository_rule, not intended for public use.
42
+ #
43
+ # See ./private/toolchains_repo.bzl
44
+ multi_pip_parse = _multi_pip_parse
45
+ whl_library_alias = _whl_library_alias
0 commit comments