Skip to content

Commit acea44a

Browse files
committed
Merge branch 'main' into uv-lock-rule-instead-of-genrule
2 parents 2b76cc8 + 5a8f6c4 commit acea44a

29 files changed

+1568
-307
lines changed

CHANGELOG.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,22 @@ Unreleased changes template.
5555
* (deps) platforms 0.0.4 -> 0.0.11
5656
* (py_wheel) Package `py_library.pyi_srcs` (`.pyi` files) in the wheel.
5757
* (py_package) Package `py_library.pyi_srcs` (`.pyi` files) in `py_package`.
58+
* (gazelle) The generated manifest file (default: `gazelle_python.yaml`) will now include the
59+
YAML document start `---` line. Implemented in
60+
[#2656](https://github.com/bazelbuild/rules_python/pull/2656).
5861

5962
{#v0-0-0-fixed}
6063
### Fixed
6164
* (pypi) The `ppc64le` is now pointing to the right target in the `platforms` package.
62-
* (gazelle) No longer incorrectly merge `py_binary` targets during partial updates in
65+
* (gazelle) No longer incorrectly merge `py_binary` targets during partial updates in
6366
`file` generation mode. Fixed in [#2619](https://github.com/bazelbuild/rules_python/pull/2619).
6467
* (bzlmod) Running as root is no longer an error. `ignore_root_user_error=True`
6568
is now the default. Note that running as root may still cause spurious
6669
Bazel cache invalidation
6770
([#1169](https://github.com/bazelbuild/rules_python/issues/1169)).
6871
* (gazelle) Don't collapse depsets to a list or into args when generating the modules mapping file.
6972
Support spilling modules mapping args into a params file.
73+
* (coverage) Fix missing files in the coverage report if they have no tests.
7074
* (pypi) From now on `python` invocations in repository and module extension
7175
evaluation contexts will invoke Python interpreter with `-B` to avoid
7276
creating `.pyc` files.
@@ -77,8 +81,16 @@ Unreleased changes template.
7781
* {obj}`//python/bin:python`: convenience target for directly running an
7882
interpreter. {obj}`--//python/bin:python_src` can be used to specify a
7983
binary whose interpreter to use.
84+
* (uv) Now the extension can be fully configured via `bzlmod` APIs without the
85+
need to patch `rules_python`. The documentation has been added to `rules_python`
86+
docs but usage of the extension may result in your setup breaking without any
87+
notice. What is more, the URLs and SHA256 values will be retrieved from the
88+
GitHub releases page metadata published by the `uv` project.
8089
* (pypi) An extra argument to add the interpreter lib dir to `LDFLAGS` when
8190
building wheels from `sdist`.
91+
* (pypi) Direct HTTP urls for wheels and sdists are now supported when using
92+
{obj}`experimental_index_url` (bazel downloader).
93+
Partially fixes [#2363](https://github.com/bazelbuild/rules_python/issues/2363).
8294

8395
{#v0-0-0-removed}
8496
### Removed

MODULE.bazel

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -174,16 +174,83 @@ use_repo(
174174
"build_bazel_bazel_self",
175175
)
176176

177-
# EXPERIMENTAL: This is experimental and may be removed without notice
178-
uv = use_extension(
177+
# TODO @aignas 2025-01-27: should this be moved to `//python/extensions:uv.bzl` or should
178+
# it stay as it is? I think I may prefer to move it.
179+
uv = use_extension("//python/uv:uv.bzl", "uv")
180+
181+
# Here is how we can define platforms for the `uv` binaries - this will affect
182+
# all of the downstream callers because we are using the extension without
183+
# `dev_dependency = True`.
184+
uv.default(
185+
base_url = "https://github.com/astral-sh/uv/releases/download",
186+
manifest_filename = "dist-manifest.json",
187+
version = "0.6.3",
188+
)
189+
uv.default(
190+
compatible_with = [
191+
"@platforms//os:macos",
192+
"@platforms//cpu:aarch64",
193+
],
194+
platform = "aarch64-apple-darwin",
195+
)
196+
uv.default(
197+
compatible_with = [
198+
"@platforms//os:linux",
199+
"@platforms//cpu:aarch64",
200+
],
201+
platform = "aarch64-unknown-linux-gnu",
202+
)
203+
uv.default(
204+
compatible_with = [
205+
"@platforms//os:linux",
206+
"@platforms//cpu:ppc",
207+
],
208+
platform = "powerpc64-unknown-linux-gnu",
209+
)
210+
uv.default(
211+
compatible_with = [
212+
"@platforms//os:linux",
213+
"@platforms//cpu:ppc64le",
214+
],
215+
platform = "powerpc64le-unknown-linux-gnu",
216+
)
217+
uv.default(
218+
compatible_with = [
219+
"@platforms//os:linux",
220+
"@platforms//cpu:s390x",
221+
],
222+
platform = "s390x-unknown-linux-gnu",
223+
)
224+
uv.default(
225+
compatible_with = [
226+
"@platforms//os:macos",
227+
"@platforms//cpu:x86_64",
228+
],
229+
platform = "x86_64-apple-darwin",
230+
)
231+
uv.default(
232+
compatible_with = [
233+
"@platforms//os:windows",
234+
"@platforms//cpu:x86_64",
235+
],
236+
platform = "x86_64-pc-windows-msvc",
237+
)
238+
uv.default(
239+
compatible_with = [
240+
"@platforms//os:linux",
241+
"@platforms//cpu:x86_64",
242+
],
243+
platform = "x86_64-unknown-linux-gnu",
244+
)
245+
use_repo(uv, "uv")
246+
247+
register_toolchains("@uv//:all")
248+
249+
uv_dev = use_extension(
179250
"//python/uv:uv.bzl",
180251
"uv",
181252
dev_dependency = True,
182253
)
183-
uv.toolchain(uv_version = "0.4.25")
184-
use_repo(uv, "uv_toolchains")
185-
186-
register_toolchains(
187-
"@uv_toolchains//:all",
188-
dev_dependency = True,
254+
uv_dev.configure(
255+
version = "0.6.2",
189256
)

docs/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ lock(
172172
args = [
173173
"--emit-index-url",
174174
"--universal",
175-
"--upgrade",
175+
#"--upgrade",
176176
],
177177
visibility = ["//private:__pkg__"],
178178
)

examples/build_file_generation/gazelle_python.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# To update this file, run:
44
# bazel run //:gazelle_python_manifest.update
55

6+
---
67
manifest:
78
modules_mapping:
89
alabaster: alabaster

examples/bzlmod/.python_version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.9

examples/bzlmod/MODULE.bazel

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,15 @@ python.single_version_platform_override(
101101
# rules based on the `python_version` arg values.
102102
use_repo(python, "python_3_10", "python_3_9", "python_versions", "pythons_hub")
103103

104-
# EXPERIMENTAL: This is experimental and may be removed without notice
105-
uv = use_extension("@rules_python//python/uv:uv.bzl", "uv")
106-
uv.toolchain(uv_version = "0.4.25")
107-
use_repo(uv, "uv_toolchains")
108-
109-
register_toolchains("@uv_toolchains//:all")
104+
# EXPERIMENTAL: This is experimental and may be changed or removed without notice
105+
uv = use_extension(
106+
"@rules_python//python/uv:uv.bzl",
107+
"uv",
108+
# Use `dev_dependency` so that the toolchains are not defined pulled when your
109+
# module is used elsewhere.
110+
dev_dependency = True,
111+
)
112+
uv.configure(version = "0.6.2")
110113

111114
# This extension allows a user to create modifications to how rules_python
112115
# creates different wheel repositories. Different attributes allow the user

examples/bzlmod_build_file_generation/gazelle_python.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# To update this file, run:
44
# bazel run //:gazelle_python_manifest.update
55

6+
---
67
manifest:
78
modules_mapping:
89
S3: s3cmd

examples/bzlmod_build_file_generation/gazelle_python_with_types.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# To update this file, run:
44
# bazel run //:gazelle_python_manifest_with_types.update
55

6+
---
67
manifest:
78
modules_mapping:
89
S3: s3cmd

gazelle/manifest/generate/generate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ func writeOutput(
151151
}
152152
defer outputFile.Close()
153153

154-
if _, err := fmt.Fprintf(outputFile, "%s\n", header); err != nil {
154+
if _, err := fmt.Fprintf(outputFile, "%s\n---\n", header); err != nil {
155155
return fmt.Errorf("failed to write output: %w", err)
156156
}
157157

python/private/pypi/index_sources.bzl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def index_sources(line):
3232
* `marker` - str; the marker expression, as per PEP508 spec.
3333
* `requirement` - str; a requirement line without the marker. This can
3434
be given to `pip` to install a package.
35+
* `url` - str; URL if the requirement specifies a direct URL, empty string otherwise.
3536
"""
3637
line = line.replace("\\", " ")
3738
head, _, maybe_hashes = line.partition(";")
@@ -55,14 +56,18 @@ def index_sources(line):
5556
requirement,
5657
" ".join(["--hash=sha256:{}".format(sha) for sha in shas]),
5758
).strip()
59+
60+
url = ""
5861
if "@" in head:
5962
requirement = requirement_line
60-
shas = []
63+
_, _, url_and_rest = requirement.partition("@")
64+
url = url_and_rest.strip().partition(" ")[0].strip()
6165

6266
return struct(
6367
requirement = requirement,
6468
requirement_line = requirement_line,
6569
version = version,
6670
shas = sorted(shas),
6771
marker = marker,
72+
url = url,
6873
)

python/private/pypi/parse_requirements.bzl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,23 @@ def _add_dists(*, requirement, index_urls, logger = None):
292292
index_urls: The result of simpleapi_download.
293293
logger: A logger for printing diagnostic info.
294294
"""
295+
296+
# Handle direct URLs in requirements
297+
if requirement.srcs.url:
298+
url = requirement.srcs.url
299+
_, _, filename = url.rpartition("/")
300+
direct_url_dist = struct(
301+
url = url,
302+
filename = filename,
303+
sha256 = requirement.srcs.shas[0] if requirement.srcs.shas else "",
304+
yanked = False,
305+
)
306+
307+
if filename.endswith(".whl"):
308+
return [direct_url_dist], None
309+
else:
310+
return [], direct_url_dist
311+
295312
if not index_urls:
296313
return [], None
297314

python/private/python_bootstrap_template.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,12 +425,21 @@ def _RunForCoverage(python_program, main_filename, args, env,
425425
directory under the runfiles tree, and will recursively delete the
426426
runfiles directory if set.
427427
"""
428+
instrumented_files = [abs_path for abs_path, _ in InstrumentedFilePaths()]
429+
unique_dirs = {os.path.dirname(file) for file in instrumented_files}
430+
source = "\n\t".join(unique_dirs)
431+
432+
PrintVerboseCoverage("[coveragepy] Instrumented Files:\n" + "\n".join(instrumented_files))
433+
PrintVerboseCoverage("[coveragepy] Sources:\n" + "\n".join(unique_dirs))
434+
428435
# We need for coveragepy to use relative paths. This can only be configured
429436
unique_id = uuid.uuid4()
430437
rcfile_name = os.path.join(os.environ['COVERAGE_DIR'], ".coveragerc_{}".format(unique_id))
431438
with open(rcfile_name, "w") as rcfile:
432-
rcfile.write('''[run]
439+
rcfile.write(f'''[run]
433440
relative_files = True
441+
source =
442+
\t{source}
434443
''')
435444
PrintVerboseCoverage('Coverage entrypoint:', coverage_entrypoint)
436445
# First run the target Python file via coveragepy to create a .coverage

python/private/stage2_bootstrap_template.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,13 @@ def _maybe_collect_coverage(enable):
276276
yield
277277
return
278278

279+
instrumented_files = [abs_path for abs_path, _ in instrumented_file_paths()]
280+
unique_dirs = {os.path.dirname(file) for file in instrumented_files}
281+
source = "\n\t".join(unique_dirs)
282+
283+
print_verbose_coverage("Instrumented Files:\n" + "\n".join(instrumented_files))
284+
print_verbose_coverage("Sources:\n" + "\n".join(unique_dirs))
285+
279286
import uuid
280287

281288
import coverage
@@ -289,8 +296,10 @@ def _maybe_collect_coverage(enable):
289296
print_verbose_coverage("coveragerc file:", rcfile_name)
290297
with open(rcfile_name, "w") as rcfile:
291298
rcfile.write(
292-
"""[run]
299+
f"""[run]
293300
relative_files = True
301+
source =
302+
\t{source}
294303
"""
295304
)
296305
try:

python/uv/private/BUILD.bazel

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
# limitations under the License.
1414

1515
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
16-
load("//python:py_binary.bzl", "py_binary")
1716
load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") # buildifier: disable=bzl-visibility
1817

1918
exports_files(
@@ -58,20 +57,19 @@ bzl_library(
5857
name = "uv_bzl",
5958
srcs = ["uv.bzl"],
6059
visibility = ["//python/uv:__subpackages__"],
61-
deps = [":uv_repositories_bzl"],
62-
)
63-
64-
bzl_library(
65-
name = "uv_repositories_bzl",
66-
srcs = ["uv_repositories.bzl"],
67-
visibility = ["//python/uv:__subpackages__"],
6860
deps = [
6961
":toolchain_types_bzl",
62+
":uv_repository_bzl",
7063
":uv_toolchains_repo_bzl",
71-
":versions_bzl",
7264
],
7365
)
7466

67+
bzl_library(
68+
name = "uv_repository_bzl",
69+
srcs = ["uv_repository.bzl"],
70+
visibility = ["//python/uv:__subpackages__"],
71+
)
72+
7573
bzl_library(
7674
name = "uv_toolchain_bzl",
7775
srcs = ["uv_toolchain.bzl"],
@@ -94,29 +92,12 @@ bzl_library(
9492
],
9593
)
9694

97-
bzl_library(
98-
name = "versions_bzl",
99-
srcs = ["versions.bzl"],
100-
visibility = ["//python/uv:__subpackages__"],
101-
)
102-
103-
py_binary(
104-
name = "pip_compile",
105-
srcs = ["pip_compile.py"],
106-
data = [
107-
"//python/uv:current_toolchain",
108-
],
109-
tags = ["manual"],
110-
# only because this is used from a macro and we want to make the tool runable via `native_binary`.
111-
visibility = ["//visibility:public"],
112-
deps = ["//python/runfiles"],
113-
)
114-
11595
filegroup(
11696
name = "pip_compile_template",
11797
srcs = select({
11898
"@platforms//os:windows": ["//python:none"],
11999
"//conditions:default": ["pip_compile.sh"],
120100
}),
121101
target_compatible_with = [] if BZLMOD_ENABLED else ["@platforms//:incompatible"],
102+
visibility = ["//visibility:public"],
122103
)

python/uv/private/lock.bzl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def _impl2(ctx):
7171
lock_args.add("--no-strip-extras")
7272
run_args.append("--no-strip-extras")
7373

74-
update_command = "bazel run //{}:{}.update".format(
74+
update_command = "bazel run //{}:{}".format(
7575
ctx.label.package,
7676
ctx.attr.update_target,
7777
)
@@ -217,6 +217,8 @@ def lock(*, name, srcs, out, args = [], **kwargs):
217217
- Uses `uv`.
218218
- This does not error out if the output file does not exist yet.
219219
- Supports transitions out of the box.
220+
- The execution of the lock file generation is happening inside of a build
221+
action in a `genrule`.
220222
221223
Args:
222224
name: The name of the target to run for updating the requirements.

0 commit comments

Comments
 (0)