Skip to content

Commit 5c2b59f

Browse files
committed
Merge branch 'master' of github.com:mongodb/mongo-python-driver into python-ver
2 parents d61cb92 + 2149567 commit 5c2b59f

File tree

68 files changed

+3416
-1656
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+3416
-1656
lines changed

.evergreen/generated_configs/variants.yml

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ buildvariants:
4545
batchtime: 10080
4646
expansions:
4747
NO_EXT: "1"
48+
- name: other-hosts-amazon2023
49+
tasks:
50+
- name: .latest !.sync_async .sharded_cluster .auth .ssl
51+
- name: .latest !.sync_async .replica_set .noauth .ssl
52+
- name: .latest !.sync_async .standalone .noauth .nossl
53+
display_name: Other hosts Amazon2023
54+
run_on:
55+
- amazon2023-arm64-latest-large-m8g
56+
batchtime: 10080
57+
expansions:
58+
NO_EXT: "1"
4859

4960
# Atlas connect tests
5061
- name: atlas-connect-rhel8-python3.9
@@ -1216,12 +1227,12 @@ buildvariants:
12161227
# Stable api tests
12171228
- name: stable-api-require-v1-rhel8-python3.9-auth
12181229
tasks:
1219-
- name: .standalone .5.0 .noauth .nossl .sync_async
1220-
- name: .standalone .6.0 .noauth .nossl .sync_async
1221-
- name: .standalone .7.0 .noauth .nossl .sync_async
1222-
- name: .standalone .8.0 .noauth .nossl .sync_async
1223-
- name: .standalone .rapid .noauth .nossl .sync_async
1224-
- name: .standalone .latest .noauth .nossl .sync_async
1230+
- name: "!.replica_set .5.0 .noauth .nossl .sync_async"
1231+
- name: "!.replica_set .6.0 .noauth .nossl .sync_async"
1232+
- name: "!.replica_set .7.0 .noauth .nossl .sync_async"
1233+
- name: "!.replica_set .8.0 .noauth .nossl .sync_async"
1234+
- name: "!.replica_set .rapid .noauth .nossl .sync_async"
1235+
- name: "!.replica_set .latest .noauth .nossl .sync_async"
12251236
display_name: Stable API require v1 RHEL8 Python3.9 Auth
12261237
run_on:
12271238
- rhel87-small
@@ -1249,12 +1260,12 @@ buildvariants:
12491260
tags: [versionedApi_tag]
12501261
- name: stable-api-require-v1-rhel8-python3.13-auth
12511262
tasks:
1252-
- name: .standalone .5.0 .noauth .nossl .sync_async
1253-
- name: .standalone .6.0 .noauth .nossl .sync_async
1254-
- name: .standalone .7.0 .noauth .nossl .sync_async
1255-
- name: .standalone .8.0 .noauth .nossl .sync_async
1256-
- name: .standalone .rapid .noauth .nossl .sync_async
1257-
- name: .standalone .latest .noauth .nossl .sync_async
1263+
- name: "!.replica_set .5.0 .noauth .nossl .sync_async"
1264+
- name: "!.replica_set .6.0 .noauth .nossl .sync_async"
1265+
- name: "!.replica_set .7.0 .noauth .nossl .sync_async"
1266+
- name: "!.replica_set .8.0 .noauth .nossl .sync_async"
1267+
- name: "!.replica_set .rapid .noauth .nossl .sync_async"
1268+
- name: "!.replica_set .latest .noauth .nossl .sync_async"
12581269
display_name: Stable API require v1 RHEL8 Python3.13 Auth
12591270
run_on:
12601271
- rhel87-small

.evergreen/run-tests.sh

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,6 @@ else
2424
exit 1
2525
fi
2626

27-
# Source the local secrets export file if available.
28-
if [ -f "./secrets-export.sh" ]; then
29-
echo "Sourcing local secrets file"
30-
. "./secrets-export.sh"
31-
fi
32-
3327
# List the packages.
3428
uv sync ${UV_ARGS} --reinstall
3529
uv pip list

.evergreen/scripts/generate_config.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,16 @@ class Host:
7373
DEFAULT_HOST = HOSTS["rhel8"]
7474

7575
# Other hosts
76-
OTHER_HOSTS = ["RHEL9-FIPS", "RHEL8-zseries", "RHEL8-POWER8", "RHEL8-arm64"]
76+
OTHER_HOSTS = ["RHEL9-FIPS", "RHEL8-zseries", "RHEL8-POWER8", "RHEL8-arm64", "Amazon2023"]
7777
for name, run_on in zip(
78-
OTHER_HOSTS, ["rhel92-fips", "rhel8-zseries-small", "rhel8-power-small", "rhel82-arm64-small"]
78+
OTHER_HOSTS,
79+
[
80+
"rhel92-fips",
81+
"rhel8-zseries-small",
82+
"rhel8-power-small",
83+
"rhel82-arm64-small",
84+
"amazon2023-arm64-latest-large-m8g",
85+
],
7986
):
8087
HOSTS[name] = Host(name, run_on, name, dict())
8188

@@ -544,7 +551,6 @@ def create_storage_engine_variants():
544551
def create_stable_api_variants():
545552
host = DEFAULT_HOST
546553
tags = ["versionedApi_tag"]
547-
tasks = [f".standalone .{v} .noauth .nossl .sync_async" for v in get_versions_from("5.0")]
548554
variants = []
549555
types = ["require v1", "accept v2"]
550556

@@ -558,11 +564,17 @@ def create_stable_api_variants():
558564
expansions["REQUIRE_API_VERSION"] = "1"
559565
# MONGODB_API_VERSION is the apiVersion to use in the test suite.
560566
expansions["MONGODB_API_VERSION"] = "1"
567+
tasks = [
568+
f"!.replica_set .{v} .noauth .nossl .sync_async" for v in get_versions_from("5.0")
569+
]
561570
else:
562571
# Test against a cluster with acceptApiVersion2 but without
563572
# requireApiVersion, and don't automatically add apiVersion to
564573
# clients created in the test suite.
565574
expansions["ORCHESTRATION_FILE"] = "versioned-api-testing.json"
575+
tasks = [
576+
f".standalone .{v} .noauth .nossl .sync_async" for v in get_versions_from("5.0")
577+
]
566578
base_display_name = f"Stable API {test_type}"
567579
display_name = get_variant_name(base_display_name, host, python=python, **expansions)
568580
variant = create_variant(
@@ -777,9 +789,12 @@ def create_alternative_hosts_variants():
777789
handle_c_ext(C_EXTS[0], expansions)
778790
for host_name in OTHER_HOSTS:
779791
host = HOSTS[host_name]
792+
tags = [".6.0 .standalone !.sync_async"]
793+
if host_name == "Amazon2023":
794+
tags = [f".latest !.sync_async {t}" for t in SUB_TASKS]
780795
variants.append(
781796
create_variant(
782-
[".6.0 .standalone !.sync_async"],
797+
tags,
783798
display_name=get_variant_name("Other hosts", host),
784799
batchtime=batchtime,
785800
host=host,

.evergreen/scripts/run_server.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,6 @@ def start_server():
2828
elif test_name == "load_balancer":
2929
set_env("LOAD_BALANCER")
3030

31-
elif test_name == "auth_oidc":
32-
raise ValueError(
33-
"OIDC auth does not use run-orchestration directly, do not use run-server!"
34-
)
35-
3631
elif test_name == "ocsp":
3732
opts.ssl = True
3833
if "ORCHESTRATION_FILE" not in os.environ:

.evergreen/scripts/setup_tests.py

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,17 @@ def setup_libmongocrypt():
115115
run_command("chmod +x libmongocrypt/nocrypto/bin/mongocrypt.dll")
116116

117117

118-
def get_secrets(name: str) -> None:
119-
run_command(f"bash {DRIVERS_TOOLS}/.evergreen/secrets_handling/setup-secrets.sh {name}")
118+
def load_config_from_file(path: str | Path) -> dict[str, str]:
119+
config = read_env(path)
120+
for key, value in config.items():
121+
write_env(key, value)
122+
return config
123+
124+
125+
def get_secrets(name: str) -> dict[str, str]:
126+
secrets_dir = Path(f"{DRIVERS_TOOLS}/.evergreen/secrets_handling")
127+
run_command(f"bash {secrets_dir}/setup-secrets.sh {name}", cwd=secrets_dir)
128+
return load_config_from_file(secrets_dir / "secrets-export.sh")
120129

121130

122131
def handle_test_env() -> None:
@@ -158,7 +167,7 @@ def handle_test_env() -> None:
158167

159168
# Handle pass through env vars.
160169
for var in PASS_THROUGH_ENV:
161-
if is_set(var):
170+
if is_set(var) or getattr(opts, var.lower()):
162171
write_env(var, os.environ[var])
163172

164173
if extra := EXTRAS_MAP.get(test_name, ""):
@@ -189,7 +198,7 @@ def handle_test_env() -> None:
189198
AUTH = "auth"
190199

191200
if test_name == "aws_lambda":
192-
UV_ARGS.append("--with pip")
201+
UV_ARGS.append("--group pip")
193202
# Store AWS creds if they were given.
194203
if "AWS_ACCESS_KEY_ID" in os.environ:
195204
for key in ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN"]:
@@ -233,12 +242,11 @@ def handle_test_env() -> None:
233242
if is_set("MONGODB_URI"):
234243
write_env("PYMONGO_MUST_CONNECT", "true")
235244

236-
if is_set("DISABLE_TEST_COMMANDS"):
245+
if is_set("DISABLE_TEST_COMMANDS") or opts.disable_test_commands:
237246
write_env("PYMONGO_DISABLE_TEST_COMMANDS", "1")
238247

239248
if test_name == "enterprise_auth":
240-
get_secrets("drivers/enterprise_auth")
241-
config = read_env(f"{ROOT}/secrets-export.sh")
249+
config = get_secrets("drivers/enterprise_auth")
242250
if PLATFORM == "windows":
243251
LOGGER.info("Setting GSSAPI_PASS")
244252
write_env("GSSAPI_PASS", config["SASL_PASS"])
@@ -316,7 +324,7 @@ def handle_test_env() -> None:
316324
write_env("CLIENT_PEM", f"{DRIVERS_TOOLS}/.evergreen/x509gen/client.pem")
317325
write_env("CA_PEM", f"{DRIVERS_TOOLS}/.evergreen/x509gen/ca.pem")
318326

319-
compressors = os.environ.get("COMPRESSORS")
327+
compressors = os.environ.get("COMPRESSORS") or opts.compressor
320328
if compressors == "snappy":
321329
UV_ARGS.append("--extra snappy")
322330
elif compressors == "zstd":
@@ -349,13 +357,15 @@ def handle_test_env() -> None:
349357
if test_name == "encryption":
350358
if not DRIVERS_TOOLS:
351359
raise RuntimeError("Missing DRIVERS_TOOLS")
352-
run_command(f"bash {DRIVERS_TOOLS}/.evergreen/csfle/setup-secrets.sh")
353-
run_command(f"bash {DRIVERS_TOOLS}/.evergreen/csfle/start-servers.sh")
360+
csfle_dir = Path(f"{DRIVERS_TOOLS}/.evergreen/csfle")
361+
run_command(f"bash {csfle_dir}/setup-secrets.sh", cwd=csfle_dir)
362+
load_config_from_file(csfle_dir / "secrets-export.sh")
363+
run_command(f"bash {csfle_dir}/start-servers.sh")
354364

355365
if sub_test_name == "pyopenssl":
356366
UV_ARGS.append("--extra ocsp")
357367

358-
if is_set("TEST_CRYPT_SHARED"):
368+
if is_set("TEST_CRYPT_SHARED") or opts.crypt_shared:
359369
config = read_env(f"{DRIVERS_TOOLS}/mo-expansion.sh")
360370
CRYPT_SHARED_DIR = Path(config["CRYPT_SHARED_LIB_PATH"]).parent.as_posix()
361371
LOGGER.info("Using crypt_shared_dir %s", CRYPT_SHARED_DIR)
@@ -414,15 +424,15 @@ def handle_test_env() -> None:
414424

415425
# Add coverage if requested.
416426
# Only cover CPython. PyPy reports suspiciously low coverage.
417-
if is_set("COVERAGE") and platform.python_implementation() == "CPython":
427+
if (is_set("COVERAGE") or opts.cov) and platform.python_implementation() == "CPython":
418428
# Keep in sync with combine-coverage.sh.
419429
# coverage >=5 is needed for relative_files=true.
420430
UV_ARGS.append("--group coverage")
421431
TEST_ARGS = f"{TEST_ARGS} --cov"
422432
write_env("COVERAGE")
423433

424-
if is_set("GREEN_FRAMEWORK"):
425-
framework = os.environ["GREEN_FRAMEWORK"]
434+
if is_set("GREEN_FRAMEWORK") or opts.green_framework:
435+
framework = opts.green_framework or os.environ["GREEN_FRAMEWORK"]
426436
UV_ARGS.append(f"--group {framework}")
427437

428438
else:

.evergreen/scripts/utils.py

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ class Distro:
5252
# Tests that require a sub test suite.
5353
SUB_TEST_REQUIRED = ["auth_aws", "auth_oidc", "kms", "mod_wsgi", "perf"]
5454

55-
EXTRA_TESTS = ["mod_wsgi", "aws_lambda", "search_index"]
55+
EXTRA_TESTS = ["mod_wsgi", "aws_lambda"]
56+
57+
# Tests that do not use run-orchestration.
58+
NO_RUN_ORCHESTRATION = ["auth_oidc", "atlas_connect", "data_lake", "mockupdb", "serverless"]
5659

5760

5861
def get_test_options(
@@ -75,19 +78,47 @@ def get_test_options(
7578
else:
7679
parser.add_argument(
7780
"test_name",
78-
choices=sorted(TEST_SUITE_MAP),
81+
choices=set(TEST_SUITE_MAP) - set(NO_RUN_ORCHESTRATION),
7982
nargs="?",
8083
default="default",
8184
help="The optional name of the test suite to be run, which informs the server configuration.",
8285
)
8386
parser.add_argument(
84-
"--verbose", "-v", action="store_true", help="Whether to log at the DEBUG level"
87+
"--verbose", "-v", action="store_true", help="Whether to log at the DEBUG level."
8588
)
8689
parser.add_argument(
87-
"--quiet", "-q", action="store_true", help="Whether to log at the WARNING level"
90+
"--quiet", "-q", action="store_true", help="Whether to log at the WARNING level."
8891
)
89-
parser.add_argument("--auth", action="store_true", help="Whether to add authentication")
90-
parser.add_argument("--ssl", action="store_true", help="Whether to add TLS configuration")
92+
parser.add_argument("--auth", action="store_true", help="Whether to add authentication.")
93+
parser.add_argument("--ssl", action="store_true", help="Whether to add TLS configuration.")
94+
95+
# Add the test modifiers.
96+
if require_sub_test_name:
97+
parser.add_argument(
98+
"--debug-log", action="store_true", help="Enable pymongo standard logging."
99+
)
100+
parser.add_argument("--cov", action="store_true", help="Add test coverage.")
101+
parser.add_argument(
102+
"--green-framework",
103+
nargs=1,
104+
choices=["eventlet", "gevent"],
105+
help="Optional green framework to test against.",
106+
)
107+
parser.add_argument(
108+
"--compressor",
109+
nargs=1,
110+
choices=["zlib", "zstd", "snappy"],
111+
help="Optional compression algorithm.",
112+
)
113+
parser.add_argument("--crypt-shared", action="store_true", help="Test with crypt_shared.")
114+
parser.add_argument("--no-ext", action="store_true", help="Run without c extensions.")
115+
parser.add_argument(
116+
"--mongodb-api-version", choices=["1"], help="MongoDB stable API version to use."
117+
)
118+
parser.add_argument(
119+
"--disable-test-commands", action="store_true", help="Disable test commands."
120+
)
121+
91122
# Get the options.
92123
if not allow_extra_opts:
93124
opts, extra_opts = parser.parse_args(), []
@@ -113,7 +144,7 @@ def get_test_options(
113144
return opts, extra_opts
114145

115146

116-
def read_env(path: Path | str) -> dict[str, Any]:
147+
def read_env(path: Path | str) -> dict[str, str]:
117148
config = dict()
118149
with Path(path).open() as fid:
119150
for line in fid.readlines():

CONTRIBUTING.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,11 @@ the pages will re-render and the browser will automatically refresh.
217217

218218
### Usage
219219

220-
- Run `just run-server` with optional args to set up the server.
221-
All given flags will be passed to `run-orchestration.sh` in `$DRIVERS_TOOLS`.
220+
- Run `just run-server` with optional args to set up the server. All given options will be passed to
221+
`run-orchestration.sh` in `$DRIVERS_TOOLS`. See `$DRIVERS_TOOLS/evergreen/run-orchestration.sh -h`
222+
for a full list of options.
222223
- Run `just setup-tests` with optional args to set up the test environment, secrets, etc.
224+
See `just setup-tests -h` for a full list of available options.
223225
- Run `just run-tests` to run the tests in an appropriate Python environment.
224226
- When done, run `just teardown-tests` to clean up and `just stop-server` to stop the server.
225227

@@ -346,11 +348,28 @@ If you are running one of the `no-responder` tests, omit the `run-server` step.
346348
- Run the tests: `just run-tests`.
347349

348350
## Enable Debug Logs
351+
349352
- Use `-o log_cli_level="DEBUG" -o log_cli=1` with `just test` or `pytest`.
350353
- Add `log_cli_level = "DEBUG` and `log_cli = 1` to the `tool.pytest.ini_options` section in `pyproject.toml` for Evergreen patches or to enable debug logs by default on your machine.
351354
- You can also set `DEBUG_LOG=1` and run either `just setup-tests` or `just-test`.
355+
- Finally, you can use `just setup-tests --debug-log`.
352356
- For evergreen patch builds, you can use `evergreen patch --param DEBUG_LOG=1` to enable debug logs for the patch.
353357

358+
## Adding a new test suite
359+
360+
- If adding new tests files that should only be run for that test suite, add a pytest marker to the file and add
361+
to the list of pytest markers in `pyproject.toml`. Then add the test suite to the `TEST_SUITE_MAP` in `.evergreen/scripts/utils.py`. If for some reason it is not a pytest-runnable test, add it to the list of `EXTRA_TESTS` instead.
362+
- If the test uses Atlas or otherwise doesn't use `run-orchestration.sh`, add it to the `NO_RUN_ORCHESTRATION` list in
363+
`.evergreen/scripts/utils.py`.
364+
- If there is something special required to run the local server or there is an extra flag that should always be set
365+
like `AUTH`, add that logic to `.evergreen/scripts/run_server.py`.
366+
- The bulk of the logic will typically be in `.evergreen/scripts/setup_tests.py`. This is where you should fetch secrets and make them available using `write_env`, start services, and write other env vars needed using `write_env`.
367+
- If there are any special test considerations, including not running `pytest` at all, handle it in `.evergreen/scripts/run_tests.py`.
368+
- If there are any services or atlas clusters to teardown, handle them in `.evergreen/scripts/teardown_tests.py`.
369+
- Add functions to generate the test variant(s) and task(s) to the `.evergreen/scripts/generate_config.py`.
370+
- Regenerate the test variants and tasks using the instructions in `.evergreen/scripts/generate_config.py`.
371+
- Make sure to add instructions for running the test suite to `CONTRIBUTING.md`.
372+
354373
## Re-sync Spec Tests
355374

356375
If you would like to re-sync the copy of the specification tests in the

doc/changelog.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ PyMongo 4.12 brings a number of changes including:
99
- Support for configuring DEK cache lifetime via the ``key_expiration_ms`` argument to
1010
:class:`~pymongo.encryption_options.AutoEncryptionOpts`.
1111
- Support for $lookup in CSFLE and QE supported on MongoDB 8.1+.
12+
- AsyncMongoClient no longer performs DNS resolution for "mongodb+srv://" connection strings on creation.
13+
To avoid blocking the asyncio loop, the resolution is now deferred until the client is first connected.
14+
- Added index hinting support to the
15+
:meth:`~pymongo.asynchronous.collection.AsyncCollection.distinct` and
16+
:meth:`~pymongo.collection.Collection.distinct` commands.
17+
- Deprecated the ``hedge`` parameter for
18+
:class:`~pymongo.read_preferences.PrimaryPreferred`,
19+
:class:`~pymongo.read_preferences.Secondary`,
20+
:class:`~pymongo.read_preferences.SecondaryPreferred`,
21+
:class:`~pymongo.read_preferences.Nearest`. Support for ``hedge`` will be removed in PyMongo 5.0.
1222

1323
Issues Resolved
1424
...............

pymongo/asynchronous/client_session.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,10 +458,10 @@ def _max_time_expired_error(exc: PyMongoError) -> bool:
458458

459459

460460
# From the transactions spec, all the retryable writes errors plus
461-
# WriteConcernFailed.
461+
# WriteConcernTimeout.
462462
_UNKNOWN_COMMIT_ERROR_CODES: frozenset = _RETRYABLE_ERROR_CODES | frozenset(
463463
[
464-
64, # WriteConcernFailed
464+
64, # WriteConcernTimeout
465465
50, # MaxTimeMSExpired
466466
]
467467
)

0 commit comments

Comments
 (0)