From 93b864557b5c8eb03249e85a47b1cee253257708 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 11 Sep 2026 06:45:41 -0500 Subject: [PATCH 1/8] PYTHON-6091 Pin a consistent uv binary version in CI and locally --- .evergreen/scripts/configure-env.sh | 34 +++-------- .evergreen/scripts/install-dependencies.sh | 66 +++++++++++++++++++--- .evergreen/scripts/setup-dev-env.sh | 13 +++-- .github/workflows/test-python.yml | 16 +++--- CONTRIBUTING.md | 8 +++ justfile | 5 ++ pyproject.toml | 4 ++ 7 files changed, 99 insertions(+), 47 deletions(-) diff --git a/.evergreen/scripts/configure-env.sh b/.evergreen/scripts/configure-env.sh index 8dc328aab3..572960e304 100755 --- a/.evergreen/scripts/configure-env.sh +++ b/.evergreen/scripts/configure-env.sh @@ -19,15 +19,17 @@ UV_CACHE_DIR=$PROJECT_DIRECTORY/.local/uv/cache DRIVERS_TOOLS_BINARIES="$DRIVERS_TOOLS/.bin" MONGODB_BINARIES="$DRIVERS_TOOLS/mongodb/bin" -# On Evergreen jobs, "CI" will be set, and we don't want to write to $HOME. +# On Evergreen jobs, "CI" will be set, and we don't want to write to $HOME. Put +# our binaries (uv, just, ...) in a task-local dir we control, independent of the +# drivers-tools tree. if [ "${CI:-}" == "true" ]; then - PYMONGO_BIN_DIR=${DRIVERS_TOOLS_BINARIES:-} + PYMONGO_BIN_DIR="${TMPDIR:-/tmp}/pymongo-bin" # We want to use a path that's already on PATH on spawn hosts. else PYMONGO_BIN_DIR=$HOME/cli_bin fi -PATH_EXT="$MONGODB_BINARIES:$DRIVERS_TOOLS_BINARIES:$PYMONGO_BIN_DIR:\$PATH" +PATH_EXT="$MONGODB_BINARIES:$PYMONGO_BIN_DIR:$DRIVERS_TOOLS_BINARIES:\$PATH" # Python has cygwin path problems on Windows. Detect prospective mongo-orchestration home directory if [ "Windows_NT" = "${OS:-}" ]; then # Magic variable in cygwin @@ -38,7 +40,9 @@ if [ "Windows_NT" = "${OS:-}" ]; then # Magic variable in cygwin UV_CACHE_DIR=$(cygpath -m "$UV_CACHE_DIR") DRIVERS_TOOLS_BINARIES=$(cygpath -m "$DRIVERS_TOOLS_BINARIES") MONGODB_BINARIES=$(cygpath -m "$MONGODB_BINARIES") - PYMONGO_BIN_DIR=$(cygpath -m "$PYMONGO_BIN_DIR") + # Keep PYMONGO_BIN_DIR in cygwin form so bash can search it on PATH; native + # uv gets the Windows form (via cygpath -m) inside install-dependencies.sh. + PYMONGO_BIN_DIR=$(cygpath -u "$PYMONGO_BIN_DIR") fi SCRIPT_DIR="$PROJECT_DIRECTORY/.evergreen/scripts" @@ -90,25 +94,3 @@ cat < expansion.yml DRIVERS_TOOLS: "$DRIVERS_TOOLS" PROJECT_DIRECTORY: "$PROJECT_DIRECTORY" EOT - -# If the toolchain is available, symlink binaries to the bin dir. This has to be done -# after drivers-tools is cloned, since we might be using its binary dir. -_bin_path="" -if [ "Windows_NT" == "${OS:-}" ]; then - _bin_path="/cygdrive/c/Python/Current/Scripts" -elif [ "$(uname -s)" == "Darwin" ]; then - _bin_path="/Library/Frameworks/Python.Framework/Versions/Current/bin" -else - _bin_path="/opt/python/Current/bin" -fi -if [ -d "${_bin_path}" ]; then - _suffix="" - if [ "Windows_NT" == "${OS:-}" ]; then - _suffix=".exe" - fi - echo "Symlinking binaries from toolchain" - mkdir -p $PYMONGO_BIN_DIR - ln -s ${_bin_path}/just${_suffix} $PYMONGO_BIN_DIR/just${_suffix} - ln -s ${_bin_path}/uv${_suffix} $PYMONGO_BIN_DIR/uv${_suffix} - ln -s ${_bin_path}/uvx${_suffix} $PYMONGO_BIN_DIR/uvx${_suffix} -fi diff --git a/.evergreen/scripts/install-dependencies.sh b/.evergreen/scripts/install-dependencies.sh index 7f943d7d00..e7b9e5f23b 100755 --- a/.evergreen/scripts/install-dependencies.sh +++ b/.evergreen/scripts/install-dependencies.sh @@ -1,6 +1,6 @@ #!/bin/bash # Install the necessary dependencies. -set -eu +set -euo pipefail HERE=$(dirname ${BASH_SOURCE:-$0}) HERE="$( cd -- "$HERE" > /dev/null 2>&1 && pwd )" @@ -15,23 +15,75 @@ fi if [ -z "${PYMONGO_BIN_DIR:-}" ]; then PYMONGO_BIN_DIR="$HOME/.local/bin" fi +# uv.exe on Windows needs Windows-style paths, while bash uses the cygwin form. +# Keep PYMONGO_BIN_DIR in the form PATH uses and give uv the Windows form. +if [ "Windows_NT" = "${OS:-}" ]; then + export UV_TOOL_BIN_DIR="$(cygpath -m "$PYMONGO_BIN_DIR")" + export UV_TOOL_DIR="$(cygpath -m "${UV_TOOL_DIR:-$(dirname "$PYMONGO_BIN_DIR")/uv-tools}")" +else + export UV_TOOL_BIN_DIR="$PYMONGO_BIN_DIR" +fi + +# Locate the Python toolchain's binary dir, so we can prefer its uv and just. +_toolchain_bin="" +if [ "Windows_NT" = "${OS:-}" ]; then + _toolchain_bin="/cygdrive/c/Python/Current/Scripts" +elif [ "$(uname -s)" = "Darwin" ]; then + _toolchain_bin="/Library/Frameworks/Python.Framework/Versions/Current/bin" +else + _toolchain_bin="/opt/python/Current/bin" +fi -# Ensure uv is installed. +# Prefer the toolchain's uv as a bootstrap when uv is not already on PATH, so we +# do not fall back to installing from astral. +if ! command -v uv &>/dev/null; then + if [ -x "$_toolchain_bin/uv" ] || [ -x "$_toolchain_bin/uv.exe" ]; then + echo "Found uv in the toolchain at $_toolchain_bin" + export PATH="$_toolchain_bin:$PATH" + fi +fi + +# Ensure uv is available (bootstrap if absent). if ! command -v uv &>/dev/null; then _BIN_DIR=$PYMONGO_BIN_DIR mkdir -p ${_BIN_DIR} - echo "Installing uv..." + echo "uv not found on PATH; installing the latest uv from astral..." curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR="$_BIN_DIR" INSTALLER_NO_MODIFY_PATH=1 sh if [ "Windows_NT" = "${OS:-}" ]; then chmod +x "$(cygpath -u $_BIN_DIR)/uv.exe" fi export PATH="$PYMONGO_BIN_DIR:$PATH" - echo "Installing uv... done." fi -# Ensure just is installed. -if ! command -v just &>/dev/null; then - uv tool install rust-just +# Pin the uv binary to the version in pyproject.toml's [tool.uv] required-version. +# Run the current uv directly: it writes into PYMONGO_BIN_DIR (a different +# location), so nothing running is overwritten and no temp copy is needed. +_uv_bin="$(command -v uv 2>/dev/null || true)" +if [ -n "$_uv_bin" ]; then + _uv_pin="$(awk -F'"' '/^[[:space:]]*required-version[[:space:]]*=/{print $2}' pyproject.toml)" + _uv_vers="$(uv --version 2>/dev/null | head -1 | awk '{print $2}' | sed 's/^v//')" + if [ "uv${_uv_pin}" != "uv==${_uv_vers}" ]; then + rm -f "$PYMONGO_BIN_DIR/uv" "$PYMONGO_BIN_DIR/uv.exe" \ + "$PYMONGO_BIN_DIR/uvx" "$PYMONGO_BIN_DIR/uvx.exe" + uv tool install -q --force --from "uv${_uv_pin}" uv + echo "Using uv at $PYMONGO_BIN_DIR/uv ($("$PYMONGO_BIN_DIR/uv" --version 2>/dev/null | head -1 | awk '{print $2}'))" + fi +fi + +# Use just from the toolchain if available, otherwise install it. It must live in +# our bin dir to be on PATH for callers; copying it keeps the toolchain's just. +if [ ! -x "$PYMONGO_BIN_DIR/just" ] && [ ! -x "$PYMONGO_BIN_DIR/just.exe" ]; then + if [ -x "$_toolchain_bin/just" ]; then + echo "Using just from the toolchain" + cp "$_toolchain_bin/just" "$PYMONGO_BIN_DIR/just" + chmod +x "$PYMONGO_BIN_DIR/just" + elif [ -x "$_toolchain_bin/just.exe" ]; then + echo "Using just from the toolchain" + cp "$_toolchain_bin/just.exe" "$PYMONGO_BIN_DIR/just.exe" + chmod +x "$PYMONGO_BIN_DIR/just.exe" + else + uv tool install rust-just + fi fi popd > /dev/null diff --git a/.evergreen/scripts/setup-dev-env.sh b/.evergreen/scripts/setup-dev-env.sh index e58d6210fe..5a1794ee71 100755 --- a/.evergreen/scripts/setup-dev-env.sh +++ b/.evergreen/scripts/setup-dev-env.sh @@ -16,23 +16,24 @@ if [ -f $HERE/test-env.sh ]; then . $HERE/test-env.sh fi -# Handle the value for UV_PYTHON. -. $HERE/setup-uv-python.sh - # Ensure dependencies are installed. bash $HERE/install-dependencies.sh -# Re-source env.sh: install-dependencies.sh may have appended to it, e.g. when it -# had to install Python on an image that lacks a toolchain. +# Re-source env.sh in case a dependency install updated it, e.g. on a host +# without a toolchain where uv was installed into a shared bin dir. if [ -f $HERE/env.sh ]; then . $HERE/env.sh fi -# Add the default install path to the path if needed. +# Add the default install path to the path before configuring uv: setup-uv-python.sh +# calls uv, and on a machine without env.sh the tool dir must already be on PATH. if [ -z "${PYMONGO_BIN_DIR:-}" ]; then export PATH="$PATH:$HOME/.local/bin" fi +# Handle the value for UV_PYTHON. +. $HERE/setup-uv-python.sh + # Only run the next part if not running on CI. if [ -z "${CI:-}" ]; then # Set up venv, making sure c extensions build unless disabled. diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml index 73d5513a16..f19a783d6f 100644 --- a/.github/workflows/test-python.yml +++ b/.github/workflows/test-python.yml @@ -26,7 +26,7 @@ jobs: with: persist-credentials: false - name: Install Python tooling - uses: mongodb-labs/drivers-github-tools/python/setup@d518d2c7d04fdec10266c4218c36791a4fcf98d8 # v3.0.2 + uses: mongodb-labs/drivers-github-tools/python/setup@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3.0.5 with: python-version: "3.10" # Runs before the install so a stale lock fails in seconds rather than @@ -80,7 +80,7 @@ jobs: with: persist-credentials: false - name: Install Python tooling - uses: mongodb-labs/drivers-github-tools/python/setup@d518d2c7d04fdec10266c4218c36791a4fcf98d8 # v3.0.2 + uses: mongodb-labs/drivers-github-tools/python/setup@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3.0.5 with: # The beta Python here relies on the action's prerelease default. python-version: ${{ matrix.python-version }} @@ -102,7 +102,7 @@ jobs: with: persist-credentials: false - name: Install Python tooling - uses: mongodb-labs/drivers-github-tools/python/setup@d518d2c7d04fdec10266c4218c36791a4fcf98d8 # v3.0.2 + uses: mongodb-labs/drivers-github-tools/python/setup@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3.0.5 with: python-version: "3.10" - id: setup-mongodb @@ -127,7 +127,7 @@ jobs: with: persist-credentials: false - name: Install Python tooling - uses: mongodb-labs/drivers-github-tools/python/setup@d518d2c7d04fdec10266c4218c36791a4fcf98d8 # v3.0.2 + uses: mongodb-labs/drivers-github-tools/python/setup@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3.0.5 with: python-version: "3.10" - name: Install dependencies @@ -149,7 +149,7 @@ jobs: with: persist-credentials: false - name: Install Python tooling - uses: mongodb-labs/drivers-github-tools/python/setup@d518d2c7d04fdec10266c4218c36791a4fcf98d8 # v3.0.2 + uses: mongodb-labs/drivers-github-tools/python/setup@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3.0.5 with: python-version: "3.10" - name: Install dependencies @@ -168,7 +168,7 @@ jobs: with: persist-credentials: false - name: Install Python tooling - uses: mongodb-labs/drivers-github-tools/python/setup@d518d2c7d04fdec10266c4218c36791a4fcf98d8 # v3.0.2 + uses: mongodb-labs/drivers-github-tools/python/setup@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3.0.5 with: python-version: "${{matrix.python}}" - name: Install dependencies @@ -185,7 +185,7 @@ jobs: with: persist-credentials: false - name: Install Python tooling - uses: mongodb-labs/drivers-github-tools/python/setup@d518d2c7d04fdec10266c4218c36791a4fcf98d8 # v3.0.2 + uses: mongodb-labs/drivers-github-tools/python/setup@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3.0.5 with: python-version: "3.10" - name: Install dependencies @@ -271,7 +271,7 @@ jobs: with: persist-credentials: false - name: Install Python tooling - uses: mongodb-labs/drivers-github-tools/python/setup@d518d2c7d04fdec10266c4218c36791a4fcf98d8 # v3.0.2 + uses: mongodb-labs/drivers-github-tools/python/setup@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3.0.5 with: python-version: "3.9" - id: setup-mongodb diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2ef90224c2..980a18a76d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -199,6 +199,10 @@ the pages will re-render and the browser will automatically refresh. - Run `just install` to set a local virtual environment, or you can manually create a virtual environment and run `pytest` directly. If you want to use a specific version of Python, set `UV_PYTHON` before running `just install`. + + `just install` installs the pinned version of `uv` (from `[tool.uv] required-version`) into `$HOME/.local/bin`, + so make sure that directory is on your `PATH` (it usually is). If your `uv` is a different version, `uv` fails + fast and tells you how to update. - Ensure you have started the appropriate Mongo Server(s). You can run `just run-server` with optional args to set up the server. All given options will be passed to [`run-mongodb.sh`](https://github.com/mongodb-labs/drivers-evergreen-tools/blob/master/.evergreen/run-mongodb.sh). Run `$DRIVERS_TOOLS/.evergreen/run-mongodb.sh start -h` @@ -419,6 +423,10 @@ tasks are host-agnostic. supported version of Python and use that. This ensures a consistent behavior across host types that do not have the Python toolchain (e.g. Azure VMs), by having a known version of Python with the build headers (`Python.h`) needed to build the C extensions. + - The uv binary version is pinned once in `[tool.uv] required-version` in `pyproject.toml`. + `.evergreen/scripts/install-dependencies.sh` installs it with `uv tool install`, uv enforces it locally, and + `astral-sh/setup-uv` reads it on GitHub. Bump it manually when a newer uv is needed. If uv cannot find the + requested Python, it installs it; if that fails, the task fails. - Regenerate the test variants and tasks using `pre-commit run --all-files generate-config`. - Make sure to add instructions for running the test suite to `CONTRIBUTING.md`. diff --git a/justfile b/justfile index df678cdbac..09f7fd6f33 100644 --- a/justfile +++ b/justfile @@ -1,6 +1,11 @@ # See https://just.systems/man/en/ for instructions set shell := ["bash", "-c"] +# Put the dir that holds the pinned uv first on PATH for every recipe. On CI that +# is PYMONGO_BIN_DIR (so `just install`'s uv wins over a brew/system one); locally +# it is ~/.local/bin. This matters only when a different uv is earlier on PATH. +export PATH := env_var_or_default('PYMONGO_BIN_DIR', home_directory() + '/.local/bin') + ':' + env_var('PATH') + # Commonly used command segments. typing_run := "uv run --group typing --extra aws --extra encryption --with numpy --extra ocsp --extra snappy --extra test --extra zstd" docs_run := "uv run --extra docs" diff --git a/pyproject.toml b/pyproject.toml index 346df2f427..a41e230f0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,6 +47,10 @@ Source = "https://github.com/mongodb/mongo-python-driver" Tracker = "https://jira.mongodb.org/projects/PYTHON/issues" [tool.uv] +# Pin the uv binary version across local dev, GitHub Actions, and Evergreen. +# uv enforces this locally and astral-sh/setup-uv reads it on GitHub; Evergreen +# pins it in setup-uv-python.sh. Bump manually when a newer uv is needed. +required-version = "==0.12.12" # boto3 dropped Python 3.9 support in 1.43, so the universal lock forks at # 3.10. Without a floor the pre-3.10 fork back-solves to boto3 1.7.84 (2018), # whose vendored six and invalid escape sequences break test collection. No From 10fc7a27c4e5941f4288e3f0654ff57d8edfb97b Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 11 Sep 2026 06:56:45 -0500 Subject: [PATCH 2/8] PYTHON-6091 Drop unneeded test-python action bump (uv auto-reads required-version) --- .github/workflows/test-python.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml index f19a783d6f..73d5513a16 100644 --- a/.github/workflows/test-python.yml +++ b/.github/workflows/test-python.yml @@ -26,7 +26,7 @@ jobs: with: persist-credentials: false - name: Install Python tooling - uses: mongodb-labs/drivers-github-tools/python/setup@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3.0.5 + uses: mongodb-labs/drivers-github-tools/python/setup@d518d2c7d04fdec10266c4218c36791a4fcf98d8 # v3.0.2 with: python-version: "3.10" # Runs before the install so a stale lock fails in seconds rather than @@ -80,7 +80,7 @@ jobs: with: persist-credentials: false - name: Install Python tooling - uses: mongodb-labs/drivers-github-tools/python/setup@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3.0.5 + uses: mongodb-labs/drivers-github-tools/python/setup@d518d2c7d04fdec10266c4218c36791a4fcf98d8 # v3.0.2 with: # The beta Python here relies on the action's prerelease default. python-version: ${{ matrix.python-version }} @@ -102,7 +102,7 @@ jobs: with: persist-credentials: false - name: Install Python tooling - uses: mongodb-labs/drivers-github-tools/python/setup@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3.0.5 + uses: mongodb-labs/drivers-github-tools/python/setup@d518d2c7d04fdec10266c4218c36791a4fcf98d8 # v3.0.2 with: python-version: "3.10" - id: setup-mongodb @@ -127,7 +127,7 @@ jobs: with: persist-credentials: false - name: Install Python tooling - uses: mongodb-labs/drivers-github-tools/python/setup@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3.0.5 + uses: mongodb-labs/drivers-github-tools/python/setup@d518d2c7d04fdec10266c4218c36791a4fcf98d8 # v3.0.2 with: python-version: "3.10" - name: Install dependencies @@ -149,7 +149,7 @@ jobs: with: persist-credentials: false - name: Install Python tooling - uses: mongodb-labs/drivers-github-tools/python/setup@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3.0.5 + uses: mongodb-labs/drivers-github-tools/python/setup@d518d2c7d04fdec10266c4218c36791a4fcf98d8 # v3.0.2 with: python-version: "3.10" - name: Install dependencies @@ -168,7 +168,7 @@ jobs: with: persist-credentials: false - name: Install Python tooling - uses: mongodb-labs/drivers-github-tools/python/setup@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3.0.5 + uses: mongodb-labs/drivers-github-tools/python/setup@d518d2c7d04fdec10266c4218c36791a4fcf98d8 # v3.0.2 with: python-version: "${{matrix.python}}" - name: Install dependencies @@ -185,7 +185,7 @@ jobs: with: persist-credentials: false - name: Install Python tooling - uses: mongodb-labs/drivers-github-tools/python/setup@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3.0.5 + uses: mongodb-labs/drivers-github-tools/python/setup@d518d2c7d04fdec10266c4218c36791a4fcf98d8 # v3.0.2 with: python-version: "3.10" - name: Install dependencies @@ -271,7 +271,7 @@ jobs: with: persist-credentials: false - name: Install Python tooling - uses: mongodb-labs/drivers-github-tools/python/setup@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3.0.5 + uses: mongodb-labs/drivers-github-tools/python/setup@d518d2c7d04fdec10266c4218c36791a4fcf98d8 # v3.0.2 with: python-version: "3.9" - id: setup-mongodb From 239c968c5005321e636ee7a5f784af840e1abfae Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 11 Sep 2026 07:33:48 -0500 Subject: [PATCH 3/8] PYTHON-6091 Address review: always install pinned uv and fix bin dir/comment --- .evergreen/scripts/configure-env.sh | 3 ++- .evergreen/scripts/install-dependencies.sh | 15 +++++++-------- CONTRIBUTING.md | 4 ++-- pyproject.toml | 5 +++-- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/.evergreen/scripts/configure-env.sh b/.evergreen/scripts/configure-env.sh index 572960e304..adde681285 100755 --- a/.evergreen/scripts/configure-env.sh +++ b/.evergreen/scripts/configure-env.sh @@ -68,7 +68,8 @@ export PROJECT_DIRECTORY="$PROJECT_DIRECTORY" export CARGO_HOME="$CARGO_HOME" export UV_TOOL_DIR="$UV_TOOL_DIR" export UV_CACHE_DIR="$UV_CACHE_DIR" -export UV_TOOL_BIN_DIR="$DRIVERS_TOOLS_BINARIES" +# Send uv tool installs into our own bin dir, alongside the pinned uv/just. +export UV_TOOL_BIN_DIR="$PYMONGO_BIN_DIR" export PYMONGO_BIN_DIR="$PYMONGO_BIN_DIR" export PATH="$PATH_EXT" # shellcheck disable=SC2154 diff --git a/.evergreen/scripts/install-dependencies.sh b/.evergreen/scripts/install-dependencies.sh index e7b9e5f23b..ce6f812492 100755 --- a/.evergreen/scripts/install-dependencies.sh +++ b/.evergreen/scripts/install-dependencies.sh @@ -23,6 +23,7 @@ if [ "Windows_NT" = "${OS:-}" ]; then else export UV_TOOL_BIN_DIR="$PYMONGO_BIN_DIR" fi +mkdir -p "$PYMONGO_BIN_DIR" # Locate the Python toolchain's binary dir, so we can prefer its uv and just. _toolchain_bin="" @@ -57,17 +58,15 @@ fi # Pin the uv binary to the version in pyproject.toml's [tool.uv] required-version. # Run the current uv directly: it writes into PYMONGO_BIN_DIR (a different -# location), so nothing running is overwritten and no temp copy is needed. +# location), so nothing running is overwritten and no temp copy is needed. Always +# run it (idempotent) so uv lands in our bin dir even when it already matches. _uv_bin="$(command -v uv 2>/dev/null || true)" if [ -n "$_uv_bin" ]; then _uv_pin="$(awk -F'"' '/^[[:space:]]*required-version[[:space:]]*=/{print $2}' pyproject.toml)" - _uv_vers="$(uv --version 2>/dev/null | head -1 | awk '{print $2}' | sed 's/^v//')" - if [ "uv${_uv_pin}" != "uv==${_uv_vers}" ]; then - rm -f "$PYMONGO_BIN_DIR/uv" "$PYMONGO_BIN_DIR/uv.exe" \ - "$PYMONGO_BIN_DIR/uvx" "$PYMONGO_BIN_DIR/uvx.exe" - uv tool install -q --force --from "uv${_uv_pin}" uv - echo "Using uv at $PYMONGO_BIN_DIR/uv ($("$PYMONGO_BIN_DIR/uv" --version 2>/dev/null | head -1 | awk '{print $2}'))" - fi + rm -f "$PYMONGO_BIN_DIR/uv" "$PYMONGO_BIN_DIR/uv.exe" \ + "$PYMONGO_BIN_DIR/uvx" "$PYMONGO_BIN_DIR/uvx.exe" + uv tool install -q --force --from "uv${_uv_pin}" uv + echo "Using uv at $PYMONGO_BIN_DIR/uv ($("$PYMONGO_BIN_DIR/uv" --version 2>/dev/null | head -1 | awk '{print $2}'))" fi # Use just from the toolchain if available, otherwise install it. It must live in diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 980a18a76d..e9608aaeb4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -201,8 +201,8 @@ the pages will re-render and the browser will automatically refresh. version of Python, set `UV_PYTHON` before running `just install`. `just install` installs the pinned version of `uv` (from `[tool.uv] required-version`) into `$HOME/.local/bin`, - so make sure that directory is on your `PATH` (it usually is). If your `uv` is a different version, `uv` fails - fast and tells you how to update. + so make sure that directory is on your `PATH` (it usually is). If a project `uv` command (e.g. `just test`) runs + with a different `uv` version, `uv` fails fast and tells you how to update. - Ensure you have started the appropriate Mongo Server(s). You can run `just run-server` with optional args to set up the server. All given options will be passed to [`run-mongodb.sh`](https://github.com/mongodb-labs/drivers-evergreen-tools/blob/master/.evergreen/run-mongodb.sh). Run `$DRIVERS_TOOLS/.evergreen/run-mongodb.sh start -h` diff --git a/pyproject.toml b/pyproject.toml index a41e230f0c..0323e044c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,8 +48,9 @@ Tracker = "https://jira.mongodb.org/projects/PYTHON/issues" [tool.uv] # Pin the uv binary version across local dev, GitHub Actions, and Evergreen. -# uv enforces this locally and astral-sh/setup-uv reads it on GitHub; Evergreen -# pins it in setup-uv-python.sh. Bump manually when a newer uv is needed. +# uv enforces this locally, astral-sh/setup-uv reads it on GitHub, and +# install-dependencies.sh installs it in Evergreen. Bump manually when a newer uv +# is needed. required-version = "==0.12.12" # boto3 dropped Python 3.9 support in 1.43, so the universal lock forks at # 3.10. Without a floor the pre-3.10 fork back-solves to boto3 1.7.84 (2018), From 097964a38de8a2521f768b04d229088bf99817c5 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 11 Sep 2026 07:58:18 -0500 Subject: [PATCH 4/8] PYTHON-6091 Fix shellcheck SC2155 in Windows uv path handling --- .evergreen/scripts/install-dependencies.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.evergreen/scripts/install-dependencies.sh b/.evergreen/scripts/install-dependencies.sh index ce6f812492..24a2578d49 100755 --- a/.evergreen/scripts/install-dependencies.sh +++ b/.evergreen/scripts/install-dependencies.sh @@ -18,8 +18,10 @@ fi # uv.exe on Windows needs Windows-style paths, while bash uses the cygwin form. # Keep PYMONGO_BIN_DIR in the form PATH uses and give uv the Windows form. if [ "Windows_NT" = "${OS:-}" ]; then - export UV_TOOL_BIN_DIR="$(cygpath -m "$PYMONGO_BIN_DIR")" - export UV_TOOL_DIR="$(cygpath -m "${UV_TOOL_DIR:-$(dirname "$PYMONGO_BIN_DIR")/uv-tools}")" + _uv_tool_bin="$(cygpath -m "$PYMONGO_BIN_DIR")" + _uv_tool_dir="$(cygpath -m "${UV_TOOL_DIR:-$(dirname "$PYMONGO_BIN_DIR")/uv-tools}")" + export UV_TOOL_BIN_DIR="$_uv_tool_bin" + export UV_TOOL_DIR="$_uv_tool_dir" else export UV_TOOL_BIN_DIR="$PYMONGO_BIN_DIR" fi From e484fd15777e6e175228c49cd6bfb8f8a22b9945 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 11 Sep 2026 12:41:31 -0500 Subject: [PATCH 5/8] PYTHON-6091 Source PATH from env.sh; only prepend local bin dir when it is absent --- justfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/justfile b/justfile index 09f7fd6f33..004ae38995 100644 --- a/justfile +++ b/justfile @@ -1,10 +1,10 @@ # See https://just.systems/man/en/ for instructions set shell := ["bash", "-c"] -# Put the dir that holds the pinned uv first on PATH for every recipe. On CI that -# is PYMONGO_BIN_DIR (so `just install`'s uv wins over a brew/system one); locally -# it is ~/.local/bin. This matters only when a different uv is earlier on PATH. -export PATH := env_var_or_default('PYMONGO_BIN_DIR', home_directory() + '/.local/bin') + ':' + env_var('PATH') +# On CI, env.sh (sourced by just.sh) already puts the bin dir that holds the +# pinned uv first on PATH, so only prepend ~/.local/bin locally, where there is +# no env.sh. This lets `just` find the pinned uv after `just install`. +export PATH := if env_var_or_default('PYMONGO_BIN_DIR', '') != '' { env_var('PATH') } else { home_directory() + '/.local/bin:' + env_var('PATH') } # Commonly used command segments. typing_run := "uv run --group typing --extra aws --extra encryption --with numpy --extra ocsp --extra snappy --extra test --extra zstd" From 17d616b032c9976b9ed43bdf00373bffe057769d Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 11 Sep 2026 12:58:56 -0500 Subject: [PATCH 6/8] PYTHON-6091 Use env.sh on CI and ~/.local/bin on spawn/local hosts --- .evergreen/scripts/configure-env.sh | 5 +++-- .evergreen/scripts/setup-system.sh | 10 ++++++++++ justfile | 5 ----- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.evergreen/scripts/configure-env.sh b/.evergreen/scripts/configure-env.sh index adde681285..398447207a 100755 --- a/.evergreen/scripts/configure-env.sh +++ b/.evergreen/scripts/configure-env.sh @@ -24,9 +24,10 @@ MONGODB_BINARIES="$DRIVERS_TOOLS/mongodb/bin" # drivers-tools tree. if [ "${CI:-}" == "true" ]; then PYMONGO_BIN_DIR="${TMPDIR:-/tmp}/pymongo-bin" -# We want to use a path that's already on PATH on spawn hosts. +# On spawn hosts and local dev, use the conventional ~/.local/bin which tools on +# the PATH (or the shell rc) can find. else - PYMONGO_BIN_DIR=$HOME/cli_bin + PYMONGO_BIN_DIR=$HOME/.local/bin fi PATH_EXT="$MONGODB_BINARIES:$PYMONGO_BIN_DIR:$DRIVERS_TOOLS_BINARIES:\$PATH" diff --git a/.evergreen/scripts/setup-system.sh b/.evergreen/scripts/setup-system.sh index bd7e2dd4bc..2ba8bba706 100755 --- a/.evergreen/scripts/setup-system.sh +++ b/.evergreen/scripts/setup-system.sh @@ -15,6 +15,16 @@ if [ -z "${CI:-}" ]; then bash $HERE/setup-dev-env.sh fi +# On spawn hosts / local dev (no Evergreen CI or GitHub Actions) the pinned uv and +# just live in ~/.local/bin, so make sure that is on PATH, adding it to .bashrc if +# it is not already. +if [ "${CI:-}" != "true" ] && [ "${GITHUB_ACTIONS:-}" != "true" ]; then + case ":$PATH:" in + *":$HOME/.local/bin:"*) ;; + *) echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$HOME/.bashrc" ;; + esac +fi + # Enable core dumps if enabled on the machine # Copied from https://github.com/mongodb/mongo/blob/master/etc/evergreen.yml if [ -f /proc/self/coredump_filter ]; then diff --git a/justfile b/justfile index 004ae38995..df678cdbac 100644 --- a/justfile +++ b/justfile @@ -1,11 +1,6 @@ # See https://just.systems/man/en/ for instructions set shell := ["bash", "-c"] -# On CI, env.sh (sourced by just.sh) already puts the bin dir that holds the -# pinned uv first on PATH, so only prepend ~/.local/bin locally, where there is -# no env.sh. This lets `just` find the pinned uv after `just install`. -export PATH := if env_var_or_default('PYMONGO_BIN_DIR', '') != '' { env_var('PATH') } else { home_directory() + '/.local/bin:' + env_var('PATH') } - # Commonly used command segments. typing_run := "uv run --group typing --extra aws --extra encryption --with numpy --extra ocsp --extra snappy --extra test --extra zstd" docs_run := "uv run --extra docs" From 81abd31a3f5a61e5a1dad8aa14f82d80a840c9fb Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 11 Sep 2026 13:08:49 -0500 Subject: [PATCH 7/8] PYTHON-6091 Note non-CI hosts include VMs in bin dir comment --- .evergreen/scripts/configure-env.sh | 4 ++-- .evergreen/scripts/setup-system.sh | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.evergreen/scripts/configure-env.sh b/.evergreen/scripts/configure-env.sh index 398447207a..e68907175d 100755 --- a/.evergreen/scripts/configure-env.sh +++ b/.evergreen/scripts/configure-env.sh @@ -24,8 +24,8 @@ MONGODB_BINARIES="$DRIVERS_TOOLS/mongodb/bin" # drivers-tools tree. if [ "${CI:-}" == "true" ]; then PYMONGO_BIN_DIR="${TMPDIR:-/tmp}/pymongo-bin" -# On spawn hosts and local dev, use the conventional ~/.local/bin which tools on -# the PATH (or the shell rc) can find. +# On non-CI hosts (spawn hosts, VMs such as GCP/Azure, and local dev), use the +# conventional ~/.local/bin which tools on the PATH (or the shell rc) can find. else PYMONGO_BIN_DIR=$HOME/.local/bin fi diff --git a/.evergreen/scripts/setup-system.sh b/.evergreen/scripts/setup-system.sh index 2ba8bba706..eca8375a53 100755 --- a/.evergreen/scripts/setup-system.sh +++ b/.evergreen/scripts/setup-system.sh @@ -15,9 +15,9 @@ if [ -z "${CI:-}" ]; then bash $HERE/setup-dev-env.sh fi -# On spawn hosts / local dev (no Evergreen CI or GitHub Actions) the pinned uv and -# just live in ~/.local/bin, so make sure that is on PATH, adding it to .bashrc if -# it is not already. +# On non-CI hosts (spawn hosts, VMs such as GCP/Azure, and local dev) the pinned +# uv and just live in ~/.local/bin, so make sure that is on PATH, adding it to +# .bashrc if it is not already. if [ "${CI:-}" != "true" ] && [ "${GITHUB_ACTIONS:-}" != "true" ]; then case ":$PATH:" in *":$HOME/.local/bin:"*) ;; From 04c1ef2c6e88e5bcb5070b803b82e565f79bd22c Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 11 Sep 2026 13:44:19 -0500 Subject: [PATCH 8/8] PYTHON-6091 Fix uv pin on no-toolchain hosts; avoid overwriting running uv --- .evergreen/scripts/install-dependencies.sh | 23 ++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/.evergreen/scripts/install-dependencies.sh b/.evergreen/scripts/install-dependencies.sh index 24a2578d49..ac6b54dc7c 100755 --- a/.evergreen/scripts/install-dependencies.sh +++ b/.evergreen/scripts/install-dependencies.sh @@ -60,15 +60,26 @@ fi # Pin the uv binary to the version in pyproject.toml's [tool.uv] required-version. # Run the current uv directly: it writes into PYMONGO_BIN_DIR (a different -# location), so nothing running is overwritten and no temp copy is needed. Always -# run it (idempotent) so uv lands in our bin dir even when it already matches. +# location), so nothing running is overwritten. If the running uv is already our +# pinned bin-dir uv, skip the install to avoid overwriting it (Windows refuses to +# overwrite a running executable); otherwise install so the pin lands in the bin +# dir even when the discovered uv already matches. _uv_bin="$(command -v uv 2>/dev/null || true)" if [ -n "$_uv_bin" ]; then _uv_pin="$(awk -F'"' '/^[[:space:]]*required-version[[:space:]]*=/{print $2}' pyproject.toml)" - rm -f "$PYMONGO_BIN_DIR/uv" "$PYMONGO_BIN_DIR/uv.exe" \ - "$PYMONGO_BIN_DIR/uvx" "$PYMONGO_BIN_DIR/uvx.exe" - uv tool install -q --force --from "uv${_uv_pin}" uv - echo "Using uv at $PYMONGO_BIN_DIR/uv ($("$PYMONGO_BIN_DIR/uv" --version 2>/dev/null | head -1 | awk '{print $2}'))" + case "$_uv_bin" in + "$PYMONGO_BIN_DIR"/*) + _uv_vers="$(uv --version 2>/dev/null | head -1 | awk '{print $2}' | sed 's/^v//')" + if [ "uv${_uv_pin}" != "uv==${_uv_vers}" ]; then + uv tool install -q --force --from "uv${_uv_pin}" uv + echo "Using uv at $PYMONGO_BIN_DIR/uv ($("$PYMONGO_BIN_DIR/uv" --version 2>/dev/null | head -1 | awk '{print $2}'))" + fi + ;; + *) + uv tool install -q --force --from "uv${_uv_pin}" uv + echo "Using uv at $PYMONGO_BIN_DIR/uv ($("$PYMONGO_BIN_DIR/uv" --version 2>/dev/null | head -1 | awk '{print $2}'))" + ;; + esac fi # Use just from the toolchain if available, otherwise install it. It must live in