PYTHON-5615 Use uv python when python toolchain is not available (#2597)

This commit is contained in:
Steven Silvester 2025-10-22 17:22:22 -05:00 committed by GitHub
parent ad1167d01e
commit a5f6d638b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 483 additions and 653 deletions

View File

@ -5,19 +5,12 @@
set -eu
. .evergreen/utils.sh
# Set up the virtual env.
. .evergreen/scripts/setup-dev-env.sh
uv sync --group coverage
source .venv/bin/activate
if [ -z "${PYTHON_BINARY:-}" ]; then
PYTHON_BINARY=$(find_python3)
fi
createvirtualenv "$PYTHON_BINARY" covenv
# Keep in sync with run-tests.sh
# coverage >=5 is needed for relative_files=true.
pip install -q "coverage[toml]>=5,<=7.5"
pip list
ls -la coverage/
python -m coverage combine coverage/coverage.*
python -m coverage html -d htmlcov
coverage combine coverage/coverage.*
coverage html -d htmlcov

View File

@ -101,8 +101,8 @@ functions:
- AUTH
- SSL
- ORCHESTRATION_FILE
- PYTHON_BINARY
- PYTHON_VERSION
- UV_PYTHON
- TOOLCHAIN_VERSION
- STORAGE_ENGINE
- REQUIRE_API_VERSION
- DRIVERS_TOOLS
@ -134,10 +134,10 @@ functions:
- AWS_SECRET_ACCESS_KEY
- AWS_SESSION_TOKEN
- COVERAGE
- PYTHON_BINARY
- UV_PYTHON
- LIBMONGOCRYPT_URL
- MONGODB_URI
- PYTHON_VERSION
- TOOLCHAIN_VERSION
- DISABLE_TEST_COMMANDS
- GREEN_FRAMEWORK
- NO_EXT

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@ buildvariants:
VERSION: latest
NO_EXT: "1"
REQUIRE_FIPS: "1"
PYTHON_BINARY: /usr/bin/python3.11
UV_PYTHON: /usr/bin/python3.11
tags: []
- name: other-hosts-rhel8-zseries-latest
tasks:
@ -72,7 +72,7 @@ buildvariants:
# Aws auth tests
- name: auth-aws-ubuntu-20
tasks:
- name: .auth-aws !.auth-aws-ecs
- name: .auth-aws
display_name: Auth AWS Ubuntu-20
run_on:
- ubuntu2004-small
@ -453,14 +453,12 @@ buildvariants:
SUB_TEST_NAME: pyopenssl
# Search index tests
- name: search-index-helpers-rhel8-python3.10
- name: search-index-helpers-rhel8
tasks:
- name: .search_index
display_name: Search Index Helpers RHEL8 Python3.10
display_name: Search Index Helpers RHEL8
run_on:
- rhel87-small
expansions:
PYTHON_BINARY: /opt/python/3.10/bin/python3
# Server version tests
- name: mongodb-v4.2

View File

@ -19,20 +19,14 @@ fi
# Now we can safely enable xtrace
set -o xtrace
# Install python with pip.
PYTHON_VER="python3.10"
# Install a c compiler.
apt-get -qq update < /dev/null > /dev/null
apt-get -q install -y software-properties-common
# Use openpgp to avoid gpg key timeout.
mkdir -p $HOME/.gnupg
echo "keyserver keys.openpgp.org" >> $HOME/.gnupg/gpg.conf
add-apt-repository -y 'ppa:deadsnakes/ppa'
apt-get -qq install $PYTHON_VER $PYTHON_VER-venv build-essential $PYTHON_VER-dev -y < /dev/null > /dev/null
apt-get -q install -y build-essential
export PYTHON_BINARY=$PYTHON_VER
export SET_XTRACE_ON=1
cd src
rm -rf .venv
rm -f .evergreen/scripts/test-env.sh || true
rm -f .evergreen/scripts/env.sh || true
bash ./.evergreen/just.sh setup-tests auth_aws ecs-remote
bash .evergreen/just.sh run-tests

View File

@ -37,6 +37,8 @@ cleanup_tests() {
trap "cleanup_tests" SIGINT ERR
# Start the test runner.
echo "Running tests with UV_PYTHON=${UV_PYTHON:-}..."
uv run ${UV_ARGS} --reinstall-package pymongo .evergreen/scripts/run_tests.py "$@"
echo "Running tests with UV_PYTHON=${UV_PYTHON:-}... done."
cleanup_tests

View File

@ -11,11 +11,10 @@ pushd $HERE/../.. >/dev/null
BASE_SHA="$1"
HEAD_SHA="$2"
. .evergreen/utils.sh
if [ -z "${PYTHON_BINARY:-}" ]; then
PYTHON_BINARY=$(find_python3)
fi
# Set up the virtual env.
. $HERE/setup-dev-env.sh
uv venv --seed
source .venv/bin/activate
# Use the previous commit if this was not a PR run.
if [ "$BASE_SHA" == "$HEAD_SHA" ]; then
@ -24,7 +23,6 @@ fi
function get_import_time() {
local log_file
createvirtualenv "$PYTHON_BINARY" import-venv
python -m pip install -q ".[aws,encryption,gssapi,ocsp,snappy,zstd]"
# Import once to cache modules
python -c "import pymongo"

View File

@ -356,12 +356,10 @@ def create_oidc_auth_variants():
def create_search_index_variants():
host = DEFAULT_HOST
python = CPYTHONS[0]
return [
create_variant(
[".search_index"],
get_variant_name("Search Index Helpers", host, python=python),
python=python,
get_variant_name("Search Index Helpers", host),
host=host,
)
]
@ -438,8 +436,7 @@ def create_aws_auth_variants():
for host_name in ["ubuntu20", "win64", "macos"]:
expansions = dict()
# PYTHON-5604 - we need to skip ECS tests for now.
tasks = [".auth-aws !.auth-aws-ecs"]
tasks = [".auth-aws"]
tags = []
if host_name == "macos":
tasks = [".auth-aws !.auth-aws-web-identity !.auth-aws-ecs !.auth-aws-ec2"]
@ -477,7 +474,7 @@ def create_alternative_hosts_variants():
if "fips" in host_name.lower():
expansions["REQUIRE_FIPS"] = "1"
# Use explicit Python 3.11 binary on the host since the default python3 is 3.9.
expansions["PYTHON_BINARY"] = "/usr/bin/python3.11"
expansions["UV_PYTHON"] = "/usr/bin/python3.11"
if "amazon" in host_name.lower():
tags.append("pr")
variants.append(
@ -543,7 +540,7 @@ def create_server_version_tasks():
)
server_func = FunctionCall(func="run server", vars=expansions)
test_vars = expansions.copy()
test_vars["PYTHON_VERSION"] = python
test_vars["TOOLCHAIN_VERSION"] = python
test_vars["TEST_NAME"] = f"default_{sync}"
test_func = FunctionCall(func="run tests", vars=test_vars)
tasks.append(EvgTask(name=name, tags=tags, commands=[server_func, test_func]))
@ -599,7 +596,7 @@ def create_test_non_standard_tasks():
name = get_task_name("test-non-standard", python=python, **expansions)
server_func = FunctionCall(func="run server", vars=expansions)
test_vars = expansions.copy()
test_vars["PYTHON_VERSION"] = python
test_vars["TOOLCHAIN_VERSION"] = python
test_func = FunctionCall(func="run tests", vars=test_vars)
tasks.append(EvgTask(name=name, tags=tags, commands=[server_func, test_func]))
return tasks
@ -639,7 +636,7 @@ def create_test_standard_auth_tasks():
name = get_task_name("test-standard-auth", python=python, **expansions)
server_func = FunctionCall(func="run server", vars=expansions)
test_vars = expansions.copy()
test_vars["PYTHON_VERSION"] = python
test_vars["TOOLCHAIN_VERSION"] = python
test_func = FunctionCall(func="run tests", vars=test_vars)
tasks.append(EvgTask(name=name, tags=tags, commands=[server_func, test_func]))
return tasks
@ -691,7 +688,7 @@ def create_standard_tasks():
name = get_task_name("test-standard", python=python, sync=sync, **expansions)
server_func = FunctionCall(func="run server", vars=expansions)
test_vars = expansions.copy()
test_vars["PYTHON_VERSION"] = python
test_vars["TOOLCHAIN_VERSION"] = python
test_vars["TEST_NAME"] = f"default_{sync}"
test_func = FunctionCall(func="run tests", vars=test_vars)
tasks.append(EvgTask(name=name, tags=tags, commands=[server_func, test_func]))
@ -707,7 +704,7 @@ def create_no_orchestration_tasks():
]
name = get_task_name("test-no-orchestration", python=python)
assume_func = FunctionCall(func="assume ec2 role")
test_vars = dict(PYTHON_VERSION=python)
test_vars = dict(TOOLCHAIN_VERSION=python)
test_func = FunctionCall(func="run tests", vars=test_vars)
commands = [assume_func, test_func]
tasks.append(EvgTask(name=name, tags=tags, commands=commands))
@ -756,7 +753,7 @@ def create_aws_tasks():
if "t" in python:
tags.append("free-threaded")
name = get_task_name(f"{base_name}-{test_type}", python=python)
test_vars = dict(TEST_NAME="auth_aws", SUB_TEST_NAME=test_type, PYTHON_VERSION=python)
test_vars = dict(TEST_NAME="auth_aws", SUB_TEST_NAME=test_type, TOOLCHAIN_VERSION=python)
test_func = FunctionCall(func="run tests", vars=test_vars)
funcs = [server_func, assume_func, test_func]
tasks.append(EvgTask(name=name, tags=tags, commands=funcs))
@ -768,7 +765,7 @@ def create_aws_tasks():
TEST_NAME="auth_aws",
SUB_TEST_NAME="web-identity",
AWS_ROLE_SESSION_NAME="test",
PYTHON_VERSION=python,
TOOLCHAIN_VERSION=python,
)
if "t" in python:
tags.append("free-threaded")
@ -806,9 +803,11 @@ def create_mod_wsgi_tasks():
task_name = "mod-wsgi-embedded-mode-"
task_name += topology.replace("_", "-")
task_name = get_task_name(task_name, python=python)
server_vars = dict(TOPOLOGY=topology, PYTHON_VERSION=python)
server_vars = dict(TOPOLOGY=topology, TOOLCHAIN_VERSION=python)
server_func = FunctionCall(func="run server", vars=server_vars)
vars = dict(TEST_NAME="mod_wsgi", SUB_TEST_NAME=test.split("-")[0], PYTHON_VERSION=python)
vars = dict(
TEST_NAME="mod_wsgi", SUB_TEST_NAME=test.split("-")[0], TOOLCHAIN_VERSION=python
)
test_func = FunctionCall(func="run tests", vars=vars)
tags = ["mod_wsgi", "pr"]
commands = [server_func, test_func]
@ -830,7 +829,7 @@ def _create_ocsp_tasks(algo, variant, server_type, base_task_name):
ORCHESTRATION_FILE=file_name,
OCSP_SERVER_TYPE=server_type,
TEST_NAME="ocsp",
PYTHON_VERSION=python,
TOOLCHAIN_VERSION=python,
VERSION=version,
)
test_func = FunctionCall(func="run tests", vars=vars)
@ -864,7 +863,7 @@ def create_aws_lambda_tasks():
def create_search_index_tasks():
assume_func = FunctionCall(func="assume ec2 role")
server_func = FunctionCall(func="run server", vars=dict(TEST_NAME="search_index"))
vars = dict(TEST_NAME="search_index")
vars = dict(TEST_NAME="search_index", TOOLCHAIN_VERSION=CPYTHONS[0])
test_func = FunctionCall(func="run tests", vars=vars)
task_name = "test-search-index-helpers"
tags = ["search_index"]
@ -1075,8 +1074,8 @@ def create_run_server_func():
"AUTH",
"SSL",
"ORCHESTRATION_FILE",
"PYTHON_BINARY",
"PYTHON_VERSION",
"UV_PYTHON",
"TOOLCHAIN_VERSION",
"STORAGE_ENGINE",
"REQUIRE_API_VERSION",
"DRIVERS_TOOLS",
@ -1100,10 +1099,10 @@ def create_run_tests_func():
"AWS_SECRET_ACCESS_KEY",
"AWS_SESSION_TOKEN",
"COVERAGE",
"PYTHON_BINARY",
"UV_PYTHON",
"LIBMONGOCRYPT_URL",
"MONGODB_URI",
"PYTHON_VERSION",
"TOOLCHAIN_VERSION",
"DISABLE_TEST_COMMANDS",
"GREEN_FRAMEWORK",
"NO_EXT",

View File

@ -133,43 +133,17 @@ def create_variant(
*,
version: str | None = None,
host: Host | str | None = None,
python: str | None = None,
expansions: dict | None = None,
**kwargs: Any,
) -> BuildVariant:
expansions = expansions and expansions.copy() or dict()
if version:
expansions["VERSION"] = version
if python:
expansions["PYTHON_BINARY"] = get_python_binary(python, host)
return create_variant_generic(
tasks, display_name, version=version, host=host, expansions=expansions, **kwargs
)
def get_python_binary(python: str, host: Host) -> str:
"""Get the appropriate python binary given a python version and host."""
name = host.name
if name in ["win64", "win32"]:
if name == "win32":
base = "C:/python/32"
else:
base = "C:/python"
python_dir = python.replace(".", "").replace("t", "")
return f"{base}/Python{python_dir}/python{python}.exe"
if name in ["rhel8", "ubuntu22", "ubuntu20", "rhel7"]:
return f"/opt/python/{python}/bin/python3"
if name in ["macos", "macos-arm64"]:
bin_name = "python3t" if "t" in python else "python3"
python_dir = python.replace("t", "")
framework_dir = "PythonT" if "t" in python else "Python"
return f"/Library/Frameworks/{framework_dir}.Framework/Versions/{python_dir}/bin/{bin_name}"
raise ValueError(f"no match found for python {python} on {name}")
def get_versions_from(min_version: str) -> list[str]:
"""Get all server versions starting from a minimum version."""
min_version_float = float(min_version)

View File

@ -1,5 +1,5 @@
#!/bin/bash
# Install the dependencies needed for an evergreen run.
# Install the necessary dependencies.
set -eu
HERE=$(dirname ${BASH_SOURCE:-$0})
@ -13,50 +13,6 @@ fi
# Set up the default bin directory.
if [ -z "${PYMONGO_BIN_DIR:-}" ]; then
PYMONGO_BIN_DIR="$HOME/.local/bin"
export PATH="$PYMONGO_BIN_DIR:$PATH"
fi
# Helper function to pip install a dependency using a temporary python env.
function _pip_install() {
_HERE=$(dirname ${BASH_SOURCE:-$0})
. $_HERE/../utils.sh
_VENV_PATH=$(mktemp -d)
if [ "Windows_NT" = "${OS:-}" ]; then
_VENV_PATH=$(cygpath -m $_VENV_PATH)
fi
echo "Installing $2 using pip..."
createvirtualenv "$(find_python3)" $_VENV_PATH
python -m pip install $1
_suffix=""
if [ "Windows_NT" = "${OS:-}" ]; then
_suffix=".exe"
fi
ln -s "$(which $2)" $PYMONGO_BIN_DIR/${2}${_suffix}
# uv also comes with a uvx binary.
if [ $2 == "uv" ]; then
ln -s "$(which uvx)" $PYMONGO_BIN_DIR/uvx${_suffix}
fi
echo "Installed to ${PYMONGO_BIN_DIR}"
echo "Installing $2 using pip... done."
}
# Ensure just is installed.
if ! command -v just &>/dev/null; then
# On most systems we can install directly.
_TARGET=""
if [ "Windows_NT" = "${OS:-}" ]; then
_TARGET="--target x86_64-pc-windows-msvc"
fi
_BIN_DIR=$PYMONGO_BIN_DIR
mkdir -p ${_BIN_DIR}
echo "Installing just..."
mkdir -p "$_BIN_DIR" 2>/dev/null || true
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- $_TARGET --to "$_BIN_DIR" || {
# Remove just file if it exists (can be created if there was an install error).
rm -f ${_BIN_DIR}/just
_pip_install rust-just just
}
echo "Installing just... done."
fi
# Ensure uv is installed.
@ -64,14 +20,17 @@ if ! command -v uv &>/dev/null; then
_BIN_DIR=$PYMONGO_BIN_DIR
mkdir -p ${_BIN_DIR}
echo "Installing uv..."
# On most systems we can install directly.
curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR="$_BIN_DIR" INSTALLER_NO_MODIFY_PATH=1 sh || {
_pip_install uv uv
}
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
fi
popd > /dev/null

View File

@ -33,7 +33,7 @@ def _setup_azure_vm(base_env: dict[str, str]) -> None:
env["AZUREKMS_CMD"] = "sudo apt-get install -y python3-dev build-essential"
run_command(f"{azure_dir}/run-command.sh", env=env)
env["AZUREKMS_CMD"] = "NO_EXT=1 bash .evergreen/just.sh setup-tests kms azure-remote"
env["AZUREKMS_CMD"] = "bash .evergreen/just.sh setup-tests kms azure-remote"
run_command(f"{azure_dir}/run-command.sh", env=env)
LOGGER.info("Setting up Azure VM... done.")
@ -53,7 +53,7 @@ def _setup_gcp_vm(base_env: dict[str, str]) -> None:
env["GCPKMS_CMD"] = "sudo apt-get install -y python3-dev build-essential"
run_command(f"{gcp_dir}/run-command.sh", env=env)
env["GCPKMS_CMD"] = "NO_EXT=1 bash ./.evergreen/just.sh setup-tests kms gcp-remote"
env["GCPKMS_CMD"] = "bash ./.evergreen/just.sh setup-tests kms gcp-remote"
run_command(f"{gcp_dir}/run-command.sh", env=env)
LOGGER.info("Setting up GCP VM...")

View File

@ -89,7 +89,7 @@ def test_oidc_send_to_remote(sub_test_name: str) -> None:
env[f"{upper_name}OIDC_DRIVERS_TAR_FILE"] = TMP_DRIVER_FILE
env[
f"{upper_name}OIDC_TEST_CMD"
] = f"NO_EXT=1 OIDC_ENV={sub_test_name} ./.evergreen/run-mongodb-oidc-test.sh"
] = f"OIDC_ENV={sub_test_name} ./.evergreen/run-mongodb-oidc-test.sh"
elif sub_test_name in K8S_NAMES:
env["K8S_DRIVERS_TAR_FILE"] = TMP_DRIVER_FILE
env["K8S_TEST_CMD"] = "OIDC_ENV=k8s ./.evergreen/run-mongodb-oidc-test.sh"

View File

@ -106,10 +106,11 @@ def handle_aws_lambda() -> None:
env["TEST_LAMBDA_DIRECTORY"] = str(target_dir)
env.setdefault("AWS_REGION", "us-east-1")
dirs = ["pymongo", "gridfs", "bson"]
# Store the original .so files.
before_sos = []
# Remove the original .so files.
for dname in dirs:
before_sos.extend(f"{f.parent.name}/{f.name}" for f in (ROOT / dname).glob("*.so"))
so_paths = [f"{f.parent.name}/{f.name}" for f in (ROOT / dname).glob("*.so")]
for so_path in list(so_paths):
Path(so_path).unlink()
# Build the c extensions.
docker = which("docker") or which("podman")
if not docker:
@ -122,15 +123,11 @@ def handle_aws_lambda() -> None:
target = ROOT / "test/lambda/mongodb" / dname
shutil.rmtree(target, ignore_errors=True)
shutil.copytree(ROOT / dname, target)
# Remove the original so files from the lambda directory.
for so_path in before_sos:
(ROOT / "test/lambda/mongodb" / so_path).unlink()
# Remove the new so files from the ROOT directory.
for dname in dirs:
so_paths = [f"{f.parent.name}/{f.name}" for f in (ROOT / dname).glob("*.so")]
for so_path in list(so_paths):
if so_path not in before_sos:
Path(so_path).unlink()
Path(so_path).unlink()
script_name = "run-deployed-lambda-aws-tests.sh"
run_command(f"bash {DRIVERS_TOOLS}/.evergreen/aws_lambda/{script_name}", env=env)

View File

@ -1,22 +1,17 @@
#!/bin/bash
# Set up a development environment on an evergreen host.
# Set up development environment.
set -eu
HERE=$(dirname ${BASH_SOURCE:-$0})
HERE="$( cd -- "$HERE" > /dev/null 2>&1 && pwd )"
ROOT=$(dirname "$(dirname $HERE)")
pushd $ROOT > /dev/null
# Bail early if running on GitHub Actions.
if [ -n "${GITHUB_ACTION:-}" ]; then
exit 0
fi
# Source the env files to pick up common variables.
if [ -f $HERE/env.sh ]; then
. $HERE/env.sh
fi
# PYTHON_BINARY or PYTHON_VERSION may be defined in test-env.sh.
# Get variables defined in test-env.sh.
if [ -f $HERE/test-env.sh ]; then
. $HERE/test-env.sh
fi
@ -24,36 +19,40 @@ fi
# Ensure dependencies are installed.
bash $HERE/install-dependencies.sh
# Get the appropriate UV_PYTHON.
. $ROOT/.evergreen/utils.sh
# Handle the value for UV_PYTHON.
. $HERE/setup-uv-python.sh
if [ -z "${PYTHON_BINARY:-}" ]; then
if [ -n "${PYTHON_VERSION:-}" ]; then
PYTHON_BINARY=$(get_python_binary $PYTHON_VERSION)
else
PYTHON_BINARY=$(find_python3)
# Only run the next part if not running on CI.
if [ -z "${CI:-}" ]; then
# Add the default install path to the path if needed.
if [ -z "${PYMONGO_BIN_DIR:-}" ]; then
export PATH="$PATH:$HOME/.local/bin"
fi
# Set up venv, making sure c extensions build unless disabled.
if [ -z "${NO_EXT:-}" ]; then
export PYMONGO_C_EXT_MUST_BUILD=1
fi
(
cd $ROOT && uv sync
)
# Set up build utilities on Windows spawn hosts.
if [ -f $HOME/.visualStudioEnv.sh ]; then
set +u
SSH_TTY=1 source $HOME/.visualStudioEnv.sh
set -u
fi
# Only set up pre-commit if we are in a git checkout.
if [ -f $HERE/.git ]; then
if ! command -v pre-commit &>/dev/null; then
uv tool install pre-commit
fi
fi
export UV_PYTHON=${PYTHON_BINARY}
echo "Using python $UV_PYTHON"
# Add the default install path to the path if needed.
if [ -z "${PYMONGO_BIN_DIR:-}" ]; then
export PATH="$PATH:$HOME/.local/bin"
if [ ! -f .git/hooks/pre-commit ]; then
uvx pre-commit install
fi
fi
fi
# Set up venv, making sure c extensions build unless disabled.
if [ -z "${NO_EXT:-}" ]; then
export PYMONGO_C_EXT_MUST_BUILD=1
fi
# Set up visual studio env on Windows spawn hosts.
if [ -f $HOME/.visualStudioEnv.sh ]; then
set +u
SSH_TTY=1 source $HOME/.visualStudioEnv.sh
set -u
fi
uv sync
echo "Setting up python environment... done."
popd > /dev/null

View File

@ -8,9 +8,13 @@ echo "Setting up system..."
bash .evergreen/scripts/configure-env.sh
source .evergreen/scripts/env.sh
bash $DRIVERS_TOOLS/.evergreen/setup.sh
bash .evergreen/scripts/install-dependencies.sh
popd
# Run spawn host-specific tasks.
if [ -z "${CI:-}" ]; then
bash $HERE/setup-dev-env.sh
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

View File

@ -0,0 +1,53 @@
#!/bin/bash
# Set up the UV_PYTHON variable.
set -eu
HERE=$(dirname ${BASH_SOURCE:-$0})
HERE="$( cd -- "$HERE" > /dev/null 2>&1 && pwd )"
# Use min supported version by default.
_python="3.10"
# Source the env files to pick up common variables.
if [ -f $HERE/env.sh ]; then
. $HERE/env.sh
fi
# Get variables defined in test-env.sh.
if [ -f $HERE/test-env.sh ]; then
. $HERE/test-env.sh
fi
if [ -z "${UV_PYTHON:-}" ]; then
set -x
# Translate a TOOLCHAIN_VERSION to UV_PYTHON.
if [ -n "${TOOLCHAIN_VERSION:-}" ]; then
_python=$TOOLCHAIN_VERSION
if [ "$(uname -s)" = "Darwin" ]; then
if [[ "$_python" == *"t"* ]]; then
binary_name="python3t"
framework_dir="PythonT"
else
binary_name="python3"
framework_dir="Python"
fi
_python=$(echo "$_python" | sed 's/t//g')
_python="/Library/Frameworks/$framework_dir.Framework/Versions/$_python/bin/$binary_name"
elif [ "Windows_NT" = "${OS:-}" ]; then
_python=$(echo $_python | cut -d. -f1,2 | sed 's/\.//g; s/t//g')
if [[ "$TOOLCHAIN_VERSION" == *"t"* ]]; then
_exe="python${TOOLCHAIN_VERSION}.exe"
else
_exe="python.exe"
fi
if [ -n "${IS_WIN32:-}" ]; then
_python="C:/python/32/Python${_python}/${_exe}"
else
_python="C:/python/Python${_python}/${_exe}"
fi
elif [ -d "/opt/python/$_python/bin" ]; then
_python="/opt/python/$_python/bin/python3"
fi
fi
export UV_PYTHON="$_python"
fi

View File

@ -31,8 +31,7 @@ PASS_THROUGH_ENV = [
"NO_EXT",
"MONGODB_API_VERSION",
"DEBUG_LOG",
"PYTHON_BINARY",
"PYTHON_VERSION",
"UV_PYTHON",
"REQUIRE_FIPS",
"IS_WIN32",
]

View File

@ -15,5 +15,4 @@ echo "Copying files to $target..."
rsync -az -e ssh --exclude '.git' --filter=':- .gitignore' -r . $target:$remote_dir
echo "Copying files to $target... done"
ssh $target $remote_dir/.evergreen/scripts/setup-system.sh
ssh $target "cd $remote_dir && PYTHON_BINARY=${PYTHON_BINARY:-} .evergreen/scripts/setup-dev-env.sh"
ssh $target "$remote_dir/.evergreen/scripts/setup-system.sh"

View File

@ -1,148 +0,0 @@
#!/bin/bash
# Utility functions used by pymongo evergreen scripts.
set -eu
find_python3() {
PYTHON=""
# Find a suitable toolchain version, if available.
if [ "$(uname -s)" = "Darwin" ]; then
PYTHON="/Library/Frameworks/Python.Framework/Versions/3.10/bin/python3"
elif [ "Windows_NT" = "${OS:-}" ]; then # Magic variable in cygwin
PYTHON="C:/python/Python310/python.exe"
else
# Prefer our own toolchain, fall back to mongodb toolchain if it has Python 3.10+.
if [ -f "/opt/python/3.10/bin/python3" ]; then
PYTHON="/opt/python/Current/bin/python3"
elif is_python_310 "$(command -v /opt/mongodbtoolchain/v5/bin/python3)"; then
PYTHON="/opt/mongodbtoolchain/v5/bin/python3"
elif is_python_310 "$(command -v /opt/mongodbtoolchain/v4/bin/python3)"; then
PYTHON="/opt/mongodbtoolchain/v4/bin/python3"
elif is_python_310 "$(command -v /opt/mongodbtoolchain/v3/bin/python3)"; then
PYTHON="/opt/mongodbtoolchain/v3/bin/python3"
fi
fi
# Add a fallback system python3 if it is available and Python 3.10+.
if [ -z "$PYTHON" ]; then
if is_python_310 "$(command -v python3)"; then
PYTHON="$(command -v python3)"
fi
fi
if [ -z "$PYTHON" ]; then
echo "Cannot test without python3.10+ installed!"
exit 1
fi
echo "$PYTHON"
}
# Usage:
# createvirtualenv /path/to/python /output/path/for/venv
# * param1: Python binary to use for the virtualenv
# * param2: Path to the virtualenv to create
createvirtualenv () {
PYTHON=$1
VENVPATH=$2
# Prefer venv
VENV="$PYTHON -m venv"
if [ "$(uname -s)" = "Darwin" ]; then
VIRTUALENV="$PYTHON -m virtualenv"
else
VIRTUALENV=$(command -v virtualenv 2>/dev/null || echo "$PYTHON -m virtualenv")
VIRTUALENV="$VIRTUALENV -p $PYTHON"
fi
if ! $VENV $VENVPATH 2>/dev/null; then
# Workaround for bug in older versions of virtualenv.
$VIRTUALENV $VENVPATH 2>/dev/null || $VIRTUALENV $VENVPATH
fi
if [ "Windows_NT" = "${OS:-}" ]; then
# Workaround https://bugs.python.org/issue32451:
# mongovenv/Scripts/activate: line 3: $'\r': command not found
dos2unix $VENVPATH/Scripts/activate || true
. $VENVPATH/Scripts/activate
else
. $VENVPATH/bin/activate
fi
export PIP_QUIET=1
python -m pip install --upgrade pip
}
# Usage:
# testinstall /path/to/python /path/to/.whl ["no-virtualenv"]
# * param1: Python binary to test
# * param2: Path to the wheel to install
# * param3 (optional): If set to a non-empty string, don't create a virtualenv. Used in manylinux containers.
testinstall () {
PYTHON=$1
RELEASE=$2
NO_VIRTUALENV=$3
PYTHON_IMPL=$(python -c "import platform; print(platform.python_implementation())")
if [ -z "$NO_VIRTUALENV" ]; then
createvirtualenv $PYTHON venvtestinstall
PYTHON=python
fi
$PYTHON -m pip install --upgrade $RELEASE
cd tools
if [ "$PYTHON_IMPL" = "CPython" ]; then
$PYTHON fail_if_no_c.py
fi
$PYTHON -m pip uninstall -y pymongo
cd ..
if [ -z "$NO_VIRTUALENV" ]; then
deactivate
rm -rf venvtestinstall
fi
}
# Function that returns success if the provided Python binary is version 3.10 or later
# Usage:
# is_python_310 /path/to/python
# * param1: Python binary
is_python_310() {
if [ -z "$1" ]; then
return 1
elif $1 -c "import sys; exit(sys.version_info[:2] < (3, 10))"; then
# runs when sys.version_info[:2] >= (3, 10)
return 0
else
return 1
fi
}
# Function that gets a python binary given a python version string.
# Versions can be of the form 3.xx or pypy3.xx.
get_python_binary() {
version=$1
if [ "$(uname -s)" = "Darwin" ]; then
if [[ "$version" == *"t"* ]]; then
binary_name="python3t"
framework_dir="PythonT"
else
binary_name="python3"
framework_dir="Python"
fi
version=$(echo "$version" | sed 's/t//g')
PYTHON="/Library/Frameworks/$framework_dir.Framework/Versions/$version/bin/$binary_name"
elif [ "Windows_NT" = "${OS:-}" ]; then
version=$(echo $version | cut -d. -f1,2 | sed 's/\.//g; s/t//g')
if [ -n "${IS_WIN32:-}" ]; then
PYTHON="C:/python/32/Python$version/python.exe"
else
PYTHON="C:/python/Python$version/python.exe"
fi
else
PYTHON="/opt/python/$version/bin/python3"
fi
if is_python_310 "$(command -v $PYTHON)"; then
echo "$PYTHON"
else
echo "Could not find suitable python binary for '$version'" >&2
return 1
fi
}

View File

@ -194,7 +194,7 @@ 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, remove the `.venv` folder and set `PYTHON_BINARY` before running `just install`.
version of Python, set `UV_PYTHON` before running `just install`.
- 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-orchestration.sh`](https://github.com/mongodb-labs/drivers-evergreen-tools/blob/master/.evergreen/run-orchestration.sh). Run `$DRIVERS_TOOLS/evergreen/run-orchestration.sh -h`
@ -335,7 +335,7 @@ Locally you can run:
- Run `just run-server`.
- Run `just setup-tests`.
- Run `UV_PYTHON=3.13t just run-tests`.
- Run `UV_PYTHON=3.14t just run-tests`.
### AWS Lambda tests
@ -399,6 +399,16 @@ To run any of the test suites with minimum supported dependencies, pass `--test-
- If there are any special test considerations, including not running `pytest` at all, handle it in `.evergreen/scripts/run_tests.py`.
- If there are any services or atlas clusters to teardown, handle them in `.evergreen/scripts/teardown_tests.py`.
- Add functions to generate the test variant(s) and task(s) to the `.evergreen/scripts/generate_config.py`.
- There are some considerations about the Python version used in the test:
- If a specific version of Python is needed in a task that is running on variants with a toolchain, use
``TOOLCHAIN_VERSION`` (e.g. `TOOLCHAIN_VERSION=3.10`). The actual path lookup needs to be done on the host, since
tasks are host-agnostic.
- If a specific Python binary is needed (for example on the FIPS host), set `UV_PYTHON=/path/to/python`.
- If a specific Python version is needed and the toolchain will not be available, use `UV_PYTHON` (e.g. `UV_PYTHON=3.11`).
- The default if neither ``TOOLCHAIN_VERSION`` or ``UV_PYTHON`` is set is to use UV to install the minimum
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.
- 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`.

View File

@ -18,7 +18,6 @@ resync:
install:
bash .evergreen/scripts/setup-dev-env.sh
uvx pre-commit install
[group('docs')]
docs: && resync