diff --git a/.github/actions/build-setup-common/action.yml b/.github/actions/build-setup-common/action.yml index 4be70370f9c6..a60239422aa4 100644 --- a/.github/actions/build-setup-common/action.yml +++ b/.github/actions/build-setup-common/action.yml @@ -11,13 +11,12 @@ inputs: runs: using: composite steps: - # Setup Python and related tools. - - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + # Setup Python and related tools with uv. + - name: Set up uv and Python + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 with: - # Match the min version listed in docs/project/contribution_tools.md - # or the oldest version available on the OS. - python-version: - ${{ inputs.matrix_runner == 'macos-14' && '3.11' || '3.10' }} + enable-cache: true + version: '0.11.15' - uses: ./.github/actions/build-setup-macos if: startsWith(inputs.matrix_runner, 'macos') @@ -38,9 +37,10 @@ runs: bazelisk --version echo '*** run_bazel.py' ./scripts/run_bazel.py --version - echo '*** python' - which python - python --version + echo '*** uv' + which uv + uv --version + uv python list --only-installed echo '*** clang' which clang clang --version diff --git a/.github/workflows/check_dependent_pr.yaml b/.github/workflows/check_dependent_pr.yaml index acfa2162edef..2a0e1becdeea 100644 --- a/.github/workflows/check_dependent_pr.yaml +++ b/.github/workflows/check_dependent_pr.yaml @@ -27,23 +27,25 @@ jobs: egress-policy: block allowed-endpoints: > api.github.com:443 github.com:443 pypi.org:443 - files.pythonhosted.org:443 + files.pythonhosted.org:443 raw.githubusercontent.com:443 # Note: pull_request_target checks out the base branch by default. # This is safe as it avoids running untrusted code from the PR branch. - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Install dependencies - run: | - python3 -m pip install gql==2.0.0 requests + - name: Set up uv + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + with: + enable-cache: true + version: '0.11.15' - name: Check Dependent PR run: | if [ "$EVENT_ACTION" = "closed" ]; then - python3 github_tools/check_dependent_pr.py --scan + ./github_tools/check_dependent_pr.py --scan else - python3 github_tools/check_dependent_pr.py --pr-number "${PR_NUMBER}" + ./github_tools/check_dependent_pr.py --pr-number "${PR_NUMBER}" fi env: GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/clangd_tidy.yaml b/.github/workflows/clangd_tidy.yaml index ad1e96400d9a..0faa0adcf2c8 100644 --- a/.github/workflows/clangd_tidy.yaml +++ b/.github/workflows/clangd_tidy.yaml @@ -48,6 +48,7 @@ jobs: oauth2.googleapis.com:443 objects.githubusercontent.com:443 pypi.org:443 + raw.githubusercontent.com:443 registry.npmjs.org:443 release-assets.githubusercontent.com:443 releases.bazel.build:443 @@ -75,13 +76,9 @@ jobs: if: steps.filter.outputs.has_cpp == 'true' run: ./scripts/create_compdb.py - - name: Install clangd-tidy - if: steps.filter.outputs.has_cpp == 'true' - run: pip install clangd-tidy==1.1.0.post2 - - name: Run clangd-tidy if: steps.filter.outputs.has_cpp == 'true' env: FILTER_FILES: ${{ steps.filter.outputs.has_cpp_files }} run: | - clangd-tidy -p . -j 10 $FILTER_FILES + uvx --with clangd-tidy==1.1.0.post2 clangd-tidy -p . -j 10 $FILTER_FILES diff --git a/.github/workflows/gh_pages_ci.yaml b/.github/workflows/gh_pages_ci.yaml index f77033412fe1..4bff2b5f399d 100644 --- a/.github/workflows/gh_pages_ci.yaml +++ b/.github/workflows/gh_pages_ci.yaml @@ -28,6 +28,13 @@ jobs: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Set up uv + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + with: + enable-cache: true + version: '0.11.15' + - name: Prebuild actions run: ./website/prebuild.py - name: Setup Ruby diff --git a/.github/workflows/gh_pages_deploy.yaml b/.github/workflows/gh_pages_deploy.yaml index 393580f88a35..b7488c71da11 100644 --- a/.github/workflows/gh_pages_deploy.yaml +++ b/.github/workflows/gh_pages_deploy.yaml @@ -35,6 +35,13 @@ jobs: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Set up uv + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + with: + enable-cache: true + version: '0.11.15' + - name: Prebuild actions run: ./website/prebuild.py - name: Setup Pages diff --git a/.github/workflows/nightly_release.yaml b/.github/workflows/nightly_release.yaml index 47a27ef1ccc4..84f6ac303c75 100644 --- a/.github/workflows/nightly_release.yaml +++ b/.github/workflows/nightly_release.yaml @@ -59,6 +59,7 @@ jobs: oauth2.googleapis.com:443 objects.githubusercontent.com:443 pypi.org:443 + raw.githubusercontent.com:443 registry.npmjs.org:443 release-assets.githubusercontent.com:443 releases.bazel.build:443 diff --git a/.github/workflows/pre_commit.yaml b/.github/workflows/pre_commit.yaml index e2fd6878ab00..fae5a49821f2 100644 --- a/.github/workflows/pre_commit.yaml +++ b/.github/workflows/pre_commit.yaml @@ -40,6 +40,7 @@ jobs: oauth2.googleapis.com:443 objects.githubusercontent.com:443 pypi.org:443 + raw.githubusercontent.com:443 registry.npmjs.org:443 release-assets.githubusercontent.com:443 releases.bazel.build:443 @@ -48,7 +49,6 @@ jobs: www.googleapis.com:443 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 # Ensure LLVM is set up consistently. - uses: ./.github/actions/build-setup-common diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 9f186b0e4dea..42bb855339b2 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -70,6 +70,7 @@ jobs: oauth2.googleapis.com:443 objects.githubusercontent.com:443 pypi.org:443 + raw.githubusercontent.com:443 registry.npmjs.org:443 release-assets.githubusercontent.com:443 releases.bazel.build:443 diff --git a/.gitignore b/.gitignore index b215f7729aaa..f33842af8130 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,8 @@ /examples/**/bazel-* /examples/**/MODULE.bazel.lock -# Directories created by python. +# Files and directories created by python. +uv.lock **/__pycache__/ # Ignore the user's VSCode settings and debug setup. diff --git a/bazel/version/gen_tmpl.py b/bazel/version/gen_tmpl.py index 3252bdad4a4e..19880353534b 100755 --- a/bazel/version/gen_tmpl.py +++ b/bazel/version/gen_tmpl.py @@ -1,4 +1,13 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// + +# NOTE: The `uv` shebang and inline metadata above are only used for direct +# execution of this script outside of Bazel. When executed by Bazel (e.g., as a +# tool in a rule or as a test), Bazel uses its own hermetic Python toolchain +# and ignores this metadata. """Generate a file from a template, substituting the provided key/value pairs. diff --git a/docs/project/contribution_tools.md b/docs/project/contribution_tools.md index a26ce3320c34..4869d83ee333 100644 --- a/docs/project/contribution_tools.md +++ b/docs/project/contribution_tools.md @@ -59,11 +59,10 @@ sudo apt install \ libc++abi-dev \ lld \ lldb \ - python3 \ - pipx + pre-commit -# Install pre-commit. -pipx install pre-commit +# Install `uv` for Python scripts. +curl -LsSf https://astral.sh/uv/install.sh | sh # Set up git. # If you don't already have a fork: @@ -123,7 +122,7 @@ brew install \ bazelisk \ gh \ llvm \ - python@3.10 \ + uv \ pre-commit # IMPORTANT: Make sure `llvm` is added to the PATH! It's separate from `brew`. @@ -161,13 +160,16 @@ These tools are essential for work on Carbon. - [Homebrew](https://brew.sh/) (for macOS) - To upgrade versions of `brew` packages, it will be necessary to periodically run `brew upgrade`. - - [Python](https://python.org) - - Carbon requires Python 3.10 or newer. - - To upgrade versions of pip-installed packages, it will be necessary - to periodically run `pipx list --outdated`, then - `pipx install -U ` to upgrade desired packages. - - When upgrading, version dependencies may mean packages _should_ be - outdated, and not be upgraded. + - [Python](https://python.org) using [`uv`](https://docs.astral.sh/uv/) + - Carbon uses `uv` to run Python scripts directly, ensuring automatic + dependency management. + - Standalone scripts (for example, in `scripts/`) have dependencies + embedded in the file using PEP 723 inline metadata. + - To run a script directly, ensure `uv` is installed and the script + should be runnable directly (for example, + `./scripts/create_compdb.py`). + - Installation: + https://docs.astral.sh/uv/getting-started/installation/ - Main tools - [Bazel](https://www.bazel.build/) - [Bazelisk](https://docs.bazel.build/versions/master/install-bazelisk.html): @@ -244,11 +246,6 @@ considering if they fit your workflow. - **NOTE**: This assumes you have `python` 3 installed on your system. -- [`uv`](https://docs.astral.sh/uv/): A fast Python package manager. - - Notably, `uv` supports automatic management of even complex Python - dependencies for scripts: https://docs.astral.sh/uv/guides/scripts/ - - Installation: https://docs.astral.sh/uv/getting-started/installation/ - #### Jujutsu (`jj`) [Jujutsu](https://github.com/jj-vcs/jj) is a Git-compatible version control diff --git a/github_tools/check_dependent_pr.py b/github_tools/check_dependent_pr.py index 102baee5ebf3..a8f95f9edc2c 100755 --- a/github_tools/check_dependent_pr.py +++ b/github_tools/check_dependent_pr.py @@ -1,14 +1,24 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "gql==2.0.0", +# "requests", +# "types-requests", +# ] +# /// + """Check if a PR depends on other open PRs based on shared commits. Usage examples: # Check a specific PR in dry-run mode: GITHUB_ACCESS_TOKEN=$(gh auth token) \ - python3 github_tools/check_dependent_pr.py --pr-number --dry-run + ./github_tools/check_dependent_pr.py --pr-number --dry-run # Scan all dependent PRs in dry-run mode: GITHUB_ACCESS_TOKEN=$(gh auth token) \ - python3 github_tools/check_dependent_pr.py --scan --dry-run + ./github_tools/check_dependent_pr.py --scan --dry-run """ __copyright__ = """ @@ -19,26 +29,16 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception import argparse import datetime -import importlib.util import json import re -import os import sys import requests from typing import Any, Optional -# Do some extra work to support direct runs. try: from github_tools import github_helpers except ImportError: - github_helpers_spec = importlib.util.spec_from_file_location( - "github_helpers", - os.path.join(os.path.dirname(__file__), "github_helpers.py"), - ) - assert github_helpers_spec is not None - github_helpers = importlib.util.module_from_spec(github_helpers_spec) - github_helpers_spec.loader.exec_module(github_helpers) # type: ignore - + import github_helpers # type: ignore # Queries _QUERY_OPEN_PRS = """ diff --git a/proposals/scripts/new_proposal.py b/proposals/scripts/new_proposal.py index a85375c3f800..67c93a91260f 100755 --- a/proposals/scripts/new_proposal.py +++ b/proposals/scripts/new_proposal.py @@ -1,4 +1,8 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// """Prepares a new proposal file and PR.""" diff --git a/scripts/bazel_mod_deps.py b/scripts/bazel_mod_deps.py index 768c7c4999f5..5dec2dfcd9db 100755 --- a/scripts/bazel_mod_deps.py +++ b/scripts/bazel_mod_deps.py @@ -1,4 +1,9 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// + """Run `bazel mod deps` for pre-commit. Lets pre-commit handle modifications.""" diff --git a/scripts/calculate_release_shas.py b/scripts/calculate_release_shas.py index 72198610889b..171c3a377ace 100755 --- a/scripts/calculate_release_shas.py +++ b/scripts/calculate_release_shas.py @@ -1,4 +1,9 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// + """Prints sha information for tracked tool releases.""" diff --git a/scripts/check_build_graph.py b/scripts/check_build_graph.py index 857d26723fc4..6e37bd3bf785 100755 --- a/scripts/check_build_graph.py +++ b/scripts/check_build_graph.py @@ -1,4 +1,9 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// + """Verify that the bazel build graph is in a valid state, for pre-commit.""" diff --git a/scripts/check_header_guards.py b/scripts/check_header_guards.py index 75b263f0f78d..2a40a71f7f31 100755 --- a/scripts/check_header_guards.py +++ b/scripts/check_header_guards.py @@ -1,4 +1,8 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// """Checks for missing or incorrect header guards.""" diff --git a/scripts/check_sha_filenames.py b/scripts/check_sha_filenames.py index e406ba14571e..52069477e30a 100755 --- a/scripts/check_sha_filenames.py +++ b/scripts/check_sha_filenames.py @@ -1,4 +1,9 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// + """Requires files be named for their SHA1. diff --git a/scripts/create_compdb.py b/scripts/create_compdb.py index 24e4f05e76cc..6a0c3abf8351 100755 --- a/scripts/create_compdb.py +++ b/scripts/create_compdb.py @@ -1,4 +1,9 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// + """Create a compilation database for Clang tools like `clangd`. diff --git a/scripts/fix_cc_deps.py b/scripts/fix_cc_deps.py index b3031c6bfbac..e31368cab174 100755 --- a/scripts/fix_cc_deps.py +++ b/scripts/fix_cc_deps.py @@ -1,4 +1,9 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// + """Automatically fixes bazel C++ dependencies. diff --git a/scripts/forbid_llvm_googletest.py b/scripts/forbid_llvm_googletest.py index ee0161812715..a76f4bc3d953 100755 --- a/scripts/forbid_llvm_googletest.py +++ b/scripts/forbid_llvm_googletest.py @@ -1,4 +1,9 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// + """Detects and prevents dependencies on LLVM's googletest. diff --git a/scripts/no_op_test.py b/scripts/no_op_test.py index c35d3726dcb1..e6b4f98f3a70 100644 --- a/scripts/no_op_test.py +++ b/scripts/no_op_test.py @@ -1,9 +1,9 @@ -#!/usr/bin/env python3 - """No-op test that should always pass. This is designed to have the fewest avoidable dependencies to make no-op build and test runs in CI as inexpensive as possible. + +Note that this is not designed for direct execution and is only for Bazel's use. """ __copyright__ = """ diff --git a/scripts/query_module_versions.py b/scripts/query_module_versions.py index c365800ee98d..e04fdcb3db2e 100755 --- a/scripts/query_module_versions.py +++ b/scripts/query_module_versions.py @@ -1,4 +1,9 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// + """Queries latest module versions from MODULE.bazel.""" diff --git a/scripts/run_bazel.py b/scripts/run_bazel.py index 6873ef80af4e..148ffef14662 100755 --- a/scripts/run_bazel.py +++ b/scripts/run_bazel.py @@ -1,4 +1,9 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// + """Runs bazel on arguments. diff --git a/scripts/run_bazelisk.py b/scripts/run_bazelisk.py index bc4871d46035..cb5e78c00e3c 100755 --- a/scripts/run_bazelisk.py +++ b/scripts/run_bazelisk.py @@ -1,4 +1,9 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// + """Runs bazelisk with arbitrary arguments.""" diff --git a/scripts/run_buildifier.py b/scripts/run_buildifier.py index 0cea5caceb0a..51b068a75371 100755 --- a/scripts/run_buildifier.py +++ b/scripts/run_buildifier.py @@ -1,4 +1,9 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// + """Runs buildifier on passed-in BUILD files, mainly for pre-commit.""" diff --git a/scripts/run_buildozer.py b/scripts/run_buildozer.py index 2c67fd0556d6..8ffd678502e1 100755 --- a/scripts/run_buildozer.py +++ b/scripts/run_buildozer.py @@ -1,4 +1,9 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// + """Runs buildozer on arguments. diff --git a/scripts/source_stats.py b/scripts/source_stats.py index eb8a53b26f1d..358897463998 100755 --- a/scripts/source_stats.py +++ b/scripts/source_stats.py @@ -1,4 +1,9 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// + """Script to compute statistics about source code.""" diff --git a/scripts/target_determinator.py b/scripts/target_determinator.py index 3a6f0fb45ab7..1e14ede4fa3b 100755 --- a/scripts/target_determinator.py +++ b/scripts/target_determinator.py @@ -1,4 +1,9 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// + """Computes the potentially differing rules from some git commit. diff --git a/scripts/workspace_status.py b/scripts/workspace_status.py index 571e8509acd7..20fe4609fecc 100755 --- a/scripts/workspace_status.py +++ b/scripts/workspace_status.py @@ -1,4 +1,14 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// + +# NOTE: The `uv` shebang and inline metadata above are only used for direct +# execution of this script outside of Bazel. When executed by Bazel (e.g., as a +# workspace_status_command), Bazel uses its own hermetic Python toolchain +# and ignores this metadata. + """Bazel `--workspace_status_command` script. diff --git a/toolchain/autoupdate_testdata.py b/toolchain/autoupdate_testdata.py index 6f27121ee2c9..0806be0ecb02 100755 --- a/toolchain/autoupdate_testdata.py +++ b/toolchain/autoupdate_testdata.py @@ -1,4 +1,8 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// """Autoupdates testdata in toolchain.""" diff --git a/website/prebuild.py b/website/prebuild.py index 80fca1e7ab07..b6e057e58170 100755 --- a/website/prebuild.py +++ b/website/prebuild.py @@ -1,4 +1,8 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run --script + +# /// script +# requires-python = ">=3.11" +# /// """Updates files in preparation for a jekyll build.