diff --git a/.evergreen/generated_configs/tasks.yml b/.evergreen/generated_configs/tasks.yml index 88f1fe0051..1ebce5c466 100644 --- a/.evergreen/generated_configs/tasks.yml +++ b/.evergreen/generated_configs/tasks.yml @@ -3630,121 +3630,51 @@ tasks: - free-threaded # Standard tests - - name: test-standard-v4.2-python3.11-async-noauth-ssl-replica-set + - name: test-standard-v4.4-python3.11-sync-noauth-ssl-replica-set commands: - func: run server vars: AUTH: noauth SSL: ssl TOPOLOGY: replica_set - VERSION: "4.2" + VERSION: "4.4" - func: run tests vars: AUTH: noauth SSL: ssl TOPOLOGY: replica_set - VERSION: "4.2" + VERSION: "4.4" TOOLCHAIN_VERSION: "3.11" - TEST_NAME: default_async + TEST_NAME: default_sync tags: - test-standard - - server-4.2 + - server-4.4 - python-3.11 - replica_set-noauth-ssl - - async - - name: test-standard-v4.2-python3.14t-async-noauth-ssl-replica-set + - sync + - name: test-standard-v4.4-python3.14-sync-noauth-ssl-replica-set commands: - func: run server vars: AUTH: noauth SSL: ssl TOPOLOGY: replica_set - VERSION: "4.2" + VERSION: "4.4" - func: run tests vars: AUTH: noauth SSL: ssl TOPOLOGY: replica_set - VERSION: "4.2" - TOOLCHAIN_VERSION: 3.14t - TEST_NAME: default_async - tags: - - test-standard - - server-4.2 - - python-3.14t - - replica_set-noauth-ssl - - async - - free-threaded - - name: test-standard-v4.2-python3.10-sync-noauth-nossl-standalone-min-deps - commands: - - func: run server - vars: - AUTH: noauth - SSL: nossl - TOPOLOGY: standalone - VERSION: "4.2" - TEST_MIN_DEPS: "1" - - func: run tests - vars: - AUTH: noauth - SSL: nossl - TOPOLOGY: standalone - VERSION: "4.2" - TEST_MIN_DEPS: "1" - TOOLCHAIN_VERSION: "3.10" - TEST_NAME: default_sync - tags: - - test-standard - - server-4.2 - - python-3.10 - - standalone-noauth-nossl - - sync - - name: test-standard-v4.2-python3.13-sync-noauth-nossl-standalone - commands: - - func: run server - vars: - AUTH: noauth - SSL: nossl - TOPOLOGY: standalone - VERSION: "4.2" - - func: run tests - vars: - AUTH: noauth - SSL: nossl - TOPOLOGY: standalone - VERSION: "4.2" - TOOLCHAIN_VERSION: "3.13" - TEST_NAME: default_sync - tags: - - test-standard - - server-4.2 - - python-3.13 - - standalone-noauth-nossl - - sync - - name: test-standard-v4.2-pypy3.11-sync-noauth-nossl-standalone - commands: - - func: run server - vars: - AUTH: noauth - SSL: nossl - TOPOLOGY: standalone - VERSION: "4.2" - - func: run tests - vars: - AUTH: noauth - SSL: nossl - TOPOLOGY: standalone - VERSION: "4.2" - TOOLCHAIN_VERSION: pypy3.11 + VERSION: "4.4" + TOOLCHAIN_VERSION: "3.14" TEST_NAME: default_sync tags: - test-standard - - server-4.2 - - python-pypy3.11 - - standalone-noauth-nossl + - server-4.4 + - python-3.14 + - replica_set-noauth-ssl - sync - - pypy - - name: test-standard-v4.4-python3.11-sync-auth-ssl-sharded-cluster + - name: test-standard-v4.4-python3.12-sync-auth-ssl-sharded-cluster commands: - func: run server vars: @@ -3758,15 +3688,15 @@ tasks: SSL: ssl TOPOLOGY: sharded_cluster VERSION: "4.4" - TOOLCHAIN_VERSION: "3.11" + TOOLCHAIN_VERSION: "3.12" TEST_NAME: default_sync tags: - test-standard - server-4.4 - - python-3.11 + - python-3.12 - sharded_cluster-auth-ssl - sync - - name: test-standard-v4.4-python3.14t-sync-auth-ssl-sharded-cluster + - name: test-standard-v4.4-pypy3.11-sync-auth-ssl-sharded-cluster commands: - func: run server vars: @@ -3780,16 +3710,16 @@ tasks: SSL: ssl TOPOLOGY: sharded_cluster VERSION: "4.4" - TOOLCHAIN_VERSION: 3.14t + TOOLCHAIN_VERSION: pypy3.11 TEST_NAME: default_sync tags: - test-standard - server-4.4 - - python-3.14t + - python-pypy3.11 - sharded_cluster-auth-ssl - sync - - free-threaded - - name: test-standard-v4.4-python3.10-async-noauth-nossl-standalone-min-deps + - pypy + - name: test-standard-v4.4-python3.10-sync-noauth-nossl-standalone-min-deps commands: - func: run server vars: @@ -3806,14 +3736,14 @@ tasks: VERSION: "4.4" TEST_MIN_DEPS: "1" TOOLCHAIN_VERSION: "3.10" - TEST_NAME: default_async + TEST_NAME: default_sync tags: - test-standard - server-4.4 - python-3.10 - standalone-noauth-nossl - - async - - name: test-standard-v4.4-python3.13-async-noauth-nossl-standalone + - sync + - name: test-standard-v4.4-python3.14t-sync-noauth-nossl-standalone commands: - func: run server vars: @@ -3827,38 +3757,38 @@ tasks: SSL: nossl TOPOLOGY: standalone VERSION: "4.4" - TOOLCHAIN_VERSION: "3.13" - TEST_NAME: default_async + TOOLCHAIN_VERSION: 3.14t + TEST_NAME: default_sync tags: - test-standard - server-4.4 - - python-3.13 + - python-3.14t - standalone-noauth-nossl - - async - - name: test-standard-v4.4-pypy3.11-async-noauth-nossl-standalone + - sync + - free-threaded + - name: test-standard-v5.0-python3.11-async-noauth-ssl-replica-set commands: - func: run server vars: AUTH: noauth - SSL: nossl - TOPOLOGY: standalone - VERSION: "4.4" + SSL: ssl + TOPOLOGY: replica_set + VERSION: "5.0" - func: run tests vars: AUTH: noauth - SSL: nossl - TOPOLOGY: standalone - VERSION: "4.4" - TOOLCHAIN_VERSION: pypy3.11 + SSL: ssl + TOPOLOGY: replica_set + VERSION: "5.0" + TOOLCHAIN_VERSION: "3.11" TEST_NAME: default_async tags: - test-standard - - server-4.4 - - python-pypy3.11 - - standalone-noauth-nossl + - server-5.0 + - python-3.11 + - replica_set-noauth-ssl - async - - pypy - - name: test-standard-v5.0-python3.10-sync-noauth-ssl-replica-set-min-deps + - name: test-standard-v5.0-python3.14-async-noauth-ssl-replica-set commands: - func: run server vars: @@ -3866,102 +3796,102 @@ tasks: SSL: ssl TOPOLOGY: replica_set VERSION: "5.0" - TEST_MIN_DEPS: "1" - func: run tests vars: AUTH: noauth SSL: ssl TOPOLOGY: replica_set VERSION: "5.0" - TEST_MIN_DEPS: "1" - TOOLCHAIN_VERSION: "3.10" - TEST_NAME: default_sync + TOOLCHAIN_VERSION: "3.14" + TEST_NAME: default_async tags: - test-standard - server-5.0 - - python-3.10 + - python-3.14 - replica_set-noauth-ssl - - sync - - name: test-standard-v5.0-python3.13-sync-noauth-ssl-replica-set + - async + - name: test-standard-v5.0-python3.12-async-auth-ssl-sharded-cluster commands: - func: run server vars: - AUTH: noauth + AUTH: auth SSL: ssl - TOPOLOGY: replica_set + TOPOLOGY: sharded_cluster VERSION: "5.0" - func: run tests vars: - AUTH: noauth + AUTH: auth SSL: ssl - TOPOLOGY: replica_set + TOPOLOGY: sharded_cluster VERSION: "5.0" - TOOLCHAIN_VERSION: "3.13" - TEST_NAME: default_sync + TOOLCHAIN_VERSION: "3.12" + TEST_NAME: default_async tags: - test-standard - server-5.0 - - python-3.13 - - replica_set-noauth-ssl - - sync - - name: test-standard-v5.0-pypy3.11-sync-noauth-ssl-replica-set + - python-3.12 + - sharded_cluster-auth-ssl + - async + - name: test-standard-v5.0-pypy3.11-async-auth-ssl-sharded-cluster commands: - func: run server vars: - AUTH: noauth + AUTH: auth SSL: ssl - TOPOLOGY: replica_set + TOPOLOGY: sharded_cluster VERSION: "5.0" - func: run tests vars: - AUTH: noauth + AUTH: auth SSL: ssl - TOPOLOGY: replica_set + TOPOLOGY: sharded_cluster VERSION: "5.0" TOOLCHAIN_VERSION: pypy3.11 - TEST_NAME: default_sync + TEST_NAME: default_async tags: - test-standard - server-5.0 - python-pypy3.11 - - replica_set-noauth-ssl - - sync + - sharded_cluster-auth-ssl + - async - pypy - - name: test-standard-v5.0-python3.11-async-auth-ssl-sharded-cluster + - name: test-standard-v5.0-python3.10-async-noauth-nossl-standalone-min-deps commands: - func: run server vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster + AUTH: noauth + SSL: nossl + TOPOLOGY: standalone VERSION: "5.0" + TEST_MIN_DEPS: "1" - func: run tests vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster + AUTH: noauth + SSL: nossl + TOPOLOGY: standalone VERSION: "5.0" - TOOLCHAIN_VERSION: "3.11" + TEST_MIN_DEPS: "1" + TOOLCHAIN_VERSION: "3.10" TEST_NAME: default_async tags: - test-standard - server-5.0 - - python-3.11 - - sharded_cluster-auth-ssl + - python-3.10 + - standalone-noauth-nossl - async - - name: test-standard-v5.0-python3.14t-async-auth-ssl-sharded-cluster + - name: test-standard-v5.0-python3.14t-async-noauth-nossl-standalone commands: - func: run server vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster + AUTH: noauth + SSL: nossl + TOPOLOGY: standalone VERSION: "5.0" - func: run tests vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster + AUTH: noauth + SSL: nossl + TOPOLOGY: standalone VERSION: "5.0" TOOLCHAIN_VERSION: 3.14t TEST_NAME: default_async @@ -3969,10 +3899,10 @@ tasks: - test-standard - server-5.0 - python-3.14t - - sharded_cluster-auth-ssl + - standalone-noauth-nossl - async - free-threaded - - name: test-standard-v6.0-python3.10-async-noauth-ssl-replica-set-min-deps + - name: test-standard-v6.0-python3.10-sync-noauth-ssl-replica-set-min-deps commands: - func: run server vars: @@ -3989,14 +3919,14 @@ tasks: VERSION: "6.0" TEST_MIN_DEPS: "1" TOOLCHAIN_VERSION: "3.10" - TEST_NAME: default_async + TEST_NAME: default_sync tags: - test-standard - server-6.0 - python-3.10 - replica_set-noauth-ssl - - async - - name: test-standard-v6.0-python3.13-async-noauth-ssl-replica-set + - sync + - name: test-standard-v6.0-python3.14t-sync-noauth-ssl-replica-set commands: - func: run server vars: @@ -4010,60 +3940,60 @@ tasks: SSL: ssl TOPOLOGY: replica_set VERSION: "6.0" - TOOLCHAIN_VERSION: "3.13" - TEST_NAME: default_async + TOOLCHAIN_VERSION: 3.14t + TEST_NAME: default_sync tags: - test-standard - server-6.0 - - python-3.13 + - python-3.14t - replica_set-noauth-ssl - - async - - name: test-standard-v6.0-pypy3.11-async-noauth-ssl-replica-set + - sync + - free-threaded + - name: test-standard-v6.0-python3.11-sync-auth-ssl-sharded-cluster commands: - func: run server vars: - AUTH: noauth + AUTH: auth SSL: ssl - TOPOLOGY: replica_set + TOPOLOGY: sharded_cluster VERSION: "6.0" - func: run tests vars: - AUTH: noauth + AUTH: auth SSL: ssl - TOPOLOGY: replica_set + TOPOLOGY: sharded_cluster VERSION: "6.0" - TOOLCHAIN_VERSION: pypy3.11 - TEST_NAME: default_async + TOOLCHAIN_VERSION: "3.11" + TEST_NAME: default_sync tags: - test-standard - server-6.0 - - python-pypy3.11 - - replica_set-noauth-ssl - - async - - pypy - - name: test-standard-v6.0-python3.12-sync-noauth-nossl-standalone + - python-3.11 + - sharded_cluster-auth-ssl + - sync + - name: test-standard-v6.0-python3.14-sync-auth-ssl-sharded-cluster commands: - func: run server vars: - AUTH: noauth - SSL: nossl - TOPOLOGY: standalone + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster VERSION: "6.0" - func: run tests vars: - AUTH: noauth - SSL: nossl - TOPOLOGY: standalone + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster VERSION: "6.0" - TOOLCHAIN_VERSION: "3.12" + TOOLCHAIN_VERSION: "3.14" TEST_NAME: default_sync tags: - test-standard - server-6.0 - - python-3.12 - - standalone-noauth-nossl + - python-3.14 + - sharded_cluster-auth-ssl - sync - - name: test-standard-v6.0-python3.14-sync-noauth-nossl-standalone + - name: test-standard-v6.0-python3.13-sync-noauth-nossl-standalone commands: - func: run server vars: @@ -4077,61 +4007,62 @@ tasks: SSL: nossl TOPOLOGY: standalone VERSION: "6.0" - TOOLCHAIN_VERSION: "3.14" + TOOLCHAIN_VERSION: "3.13" TEST_NAME: default_sync tags: - test-standard - server-6.0 - - python-3.14 + - python-3.13 - standalone-noauth-nossl - sync - - name: test-standard-v7.0-python3.10-sync-auth-ssl-sharded-cluster-min-deps + - name: test-standard-v7.0-python3.10-async-noauth-ssl-replica-set-min-deps commands: - func: run server vars: - AUTH: auth + AUTH: noauth SSL: ssl - TOPOLOGY: sharded_cluster + TOPOLOGY: replica_set VERSION: "7.0" TEST_MIN_DEPS: "1" - func: run tests vars: - AUTH: auth + AUTH: noauth SSL: ssl - TOPOLOGY: sharded_cluster + TOPOLOGY: replica_set VERSION: "7.0" TEST_MIN_DEPS: "1" TOOLCHAIN_VERSION: "3.10" - TEST_NAME: default_sync + TEST_NAME: default_async tags: - test-standard - server-7.0 - python-3.10 - - sharded_cluster-auth-ssl - - sync - - name: test-standard-v7.0-python3.13-sync-auth-ssl-sharded-cluster + - replica_set-noauth-ssl + - async + - name: test-standard-v7.0-python3.14t-async-noauth-ssl-replica-set commands: - func: run server vars: - AUTH: auth + AUTH: noauth SSL: ssl - TOPOLOGY: sharded_cluster + TOPOLOGY: replica_set VERSION: "7.0" - func: run tests vars: - AUTH: auth + AUTH: noauth SSL: ssl - TOPOLOGY: sharded_cluster + TOPOLOGY: replica_set VERSION: "7.0" - TOOLCHAIN_VERSION: "3.13" - TEST_NAME: default_sync + TOOLCHAIN_VERSION: 3.14t + TEST_NAME: default_async tags: - test-standard - server-7.0 - - python-3.13 - - sharded_cluster-auth-ssl - - sync - - name: test-standard-v7.0-pypy3.11-sync-auth-ssl-sharded-cluster + - python-3.14t + - replica_set-noauth-ssl + - async + - free-threaded + - name: test-standard-v7.0-python3.11-async-auth-ssl-sharded-cluster commands: - func: run server vars: @@ -4145,38 +4076,37 @@ tasks: SSL: ssl TOPOLOGY: sharded_cluster VERSION: "7.0" - TOOLCHAIN_VERSION: pypy3.11 - TEST_NAME: default_sync + TOOLCHAIN_VERSION: "3.11" + TEST_NAME: default_async tags: - test-standard - server-7.0 - - python-pypy3.11 + - python-3.11 - sharded_cluster-auth-ssl - - sync - - pypy - - name: test-standard-v7.0-python3.12-async-noauth-nossl-standalone + - async + - name: test-standard-v7.0-python3.14-async-auth-ssl-sharded-cluster commands: - func: run server vars: - AUTH: noauth - SSL: nossl - TOPOLOGY: standalone + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster VERSION: "7.0" - func: run tests vars: - AUTH: noauth - SSL: nossl - TOPOLOGY: standalone + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster VERSION: "7.0" - TOOLCHAIN_VERSION: "3.12" + TOOLCHAIN_VERSION: "3.14" TEST_NAME: default_async tags: - test-standard - server-7.0 - - python-3.12 - - standalone-noauth-nossl + - python-3.14 + - sharded_cluster-auth-ssl - async - - name: test-standard-v7.0-python3.14-async-noauth-nossl-standalone + - name: test-standard-v7.0-python3.13-async-noauth-nossl-standalone commands: - func: run server vars: @@ -4190,15 +4120,15 @@ tasks: SSL: nossl TOPOLOGY: standalone VERSION: "7.0" - TOOLCHAIN_VERSION: "3.14" + TOOLCHAIN_VERSION: "3.13" TEST_NAME: default_async tags: - test-standard - server-7.0 - - python-3.14 + - python-3.13 - standalone-noauth-nossl - async - - name: test-standard-v8.0-python3.12-sync-noauth-ssl-replica-set + - name: test-standard-v8.0-python3.13-sync-noauth-ssl-replica-set commands: - func: run server vars: @@ -4212,37 +4142,39 @@ tasks: SSL: ssl TOPOLOGY: replica_set VERSION: "8.0" - TOOLCHAIN_VERSION: "3.12" + TOOLCHAIN_VERSION: "3.13" TEST_NAME: default_sync tags: - test-standard - server-8.0 - - python-3.12 + - python-3.13 - replica_set-noauth-ssl - sync - - name: test-standard-v8.0-python3.14-sync-noauth-ssl-replica-set + - name: test-standard-v8.0-python3.10-sync-auth-ssl-sharded-cluster-min-deps commands: - func: run server vars: - AUTH: noauth + AUTH: auth SSL: ssl - TOPOLOGY: replica_set + TOPOLOGY: sharded_cluster VERSION: "8.0" + TEST_MIN_DEPS: "1" - func: run tests vars: - AUTH: noauth + AUTH: auth SSL: ssl - TOPOLOGY: replica_set + TOPOLOGY: sharded_cluster VERSION: "8.0" - TOOLCHAIN_VERSION: "3.14" + TEST_MIN_DEPS: "1" + TOOLCHAIN_VERSION: "3.10" TEST_NAME: default_sync tags: - test-standard - server-8.0 - - python-3.14 - - replica_set-noauth-ssl + - python-3.10 + - sharded_cluster-auth-ssl - sync - - name: test-standard-v8.0-python3.10-async-auth-ssl-sharded-cluster-min-deps + - name: test-standard-v8.0-python3.14t-sync-auth-ssl-sharded-cluster commands: - func: run server vars: @@ -4250,68 +4182,67 @@ tasks: SSL: ssl TOPOLOGY: sharded_cluster VERSION: "8.0" - TEST_MIN_DEPS: "1" - func: run tests vars: AUTH: auth SSL: ssl TOPOLOGY: sharded_cluster VERSION: "8.0" - TEST_MIN_DEPS: "1" - TOOLCHAIN_VERSION: "3.10" - TEST_NAME: default_async + TOOLCHAIN_VERSION: 3.14t + TEST_NAME: default_sync tags: - test-standard - server-8.0 - - python-3.10 + - python-3.14t - sharded_cluster-auth-ssl - - async - - name: test-standard-v8.0-python3.13-async-auth-ssl-sharded-cluster + - sync + - free-threaded + - name: test-standard-v8.0-python3.12-sync-noauth-nossl-standalone commands: - func: run server vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster + AUTH: noauth + SSL: nossl + TOPOLOGY: standalone VERSION: "8.0" - func: run tests vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster + AUTH: noauth + SSL: nossl + TOPOLOGY: standalone VERSION: "8.0" - TOOLCHAIN_VERSION: "3.13" - TEST_NAME: default_async + TOOLCHAIN_VERSION: "3.12" + TEST_NAME: default_sync tags: - test-standard - server-8.0 - - python-3.13 - - sharded_cluster-auth-ssl - - async - - name: test-standard-v8.0-pypy3.11-async-auth-ssl-sharded-cluster + - python-3.12 + - standalone-noauth-nossl + - sync + - name: test-standard-v8.0-pypy3.11-sync-noauth-nossl-standalone commands: - func: run server vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster + AUTH: noauth + SSL: nossl + TOPOLOGY: standalone VERSION: "8.0" - func: run tests vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster + AUTH: noauth + SSL: nossl + TOPOLOGY: standalone VERSION: "8.0" TOOLCHAIN_VERSION: pypy3.11 - TEST_NAME: default_async + TEST_NAME: default_sync tags: - test-standard - server-8.0 - python-pypy3.11 - - sharded_cluster-auth-ssl - - async + - standalone-noauth-nossl + - sync - pypy - - name: test-standard-v9.0-python3.12-async-noauth-ssl-replica-set + - name: test-standard-v9.0-python3.13-async-noauth-ssl-replica-set commands: - func: run server vars: @@ -4325,37 +4256,62 @@ tasks: SSL: ssl TOPOLOGY: replica_set VERSION: "9.0" - TOOLCHAIN_VERSION: "3.12" + TOOLCHAIN_VERSION: "3.13" TEST_NAME: default_async tags: - test-standard - server-9.0 - - python-3.12 + - python-3.13 - replica_set-noauth-ssl - async - - name: test-standard-v9.0-python3.14-async-noauth-ssl-replica-set + - name: test-standard-v9.0-python3.10-async-auth-ssl-sharded-cluster-min-deps commands: - func: run server vars: - AUTH: noauth + AUTH: auth SSL: ssl - TOPOLOGY: replica_set + TOPOLOGY: sharded_cluster VERSION: "9.0" + TEST_MIN_DEPS: "1" - func: run tests vars: - AUTH: noauth + AUTH: auth SSL: ssl - TOPOLOGY: replica_set + TOPOLOGY: sharded_cluster VERSION: "9.0" - TOOLCHAIN_VERSION: "3.14" + TEST_MIN_DEPS: "1" + TOOLCHAIN_VERSION: "3.10" TEST_NAME: default_async tags: - test-standard - server-9.0 - - python-3.14 - - replica_set-noauth-ssl + - python-3.10 + - sharded_cluster-auth-ssl + - async + - name: test-standard-v9.0-python3.14t-async-auth-ssl-sharded-cluster + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: "9.0" + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: "9.0" + TOOLCHAIN_VERSION: 3.14t + TEST_NAME: default_async + tags: + - test-standard + - server-9.0 + - python-3.14t + - sharded_cluster-auth-ssl - async - - name: test-standard-v9.0-python3.11-sync-noauth-nossl-standalone + - free-threaded + - name: test-standard-v9.0-python3.12-async-noauth-nossl-standalone commands: - func: run server vars: @@ -4369,15 +4325,15 @@ tasks: SSL: nossl TOPOLOGY: standalone VERSION: "9.0" - TOOLCHAIN_VERSION: "3.11" - TEST_NAME: default_sync + TOOLCHAIN_VERSION: "3.12" + TEST_NAME: default_async tags: - test-standard - server-9.0 - - python-3.11 + - python-3.12 - standalone-noauth-nossl - - sync - - name: test-standard-v9.0-python3.14t-sync-noauth-nossl-standalone + - async + - name: test-standard-v9.0-pypy3.11-async-noauth-nossl-standalone commands: - func: run server vars: @@ -4391,16 +4347,16 @@ tasks: SSL: nossl TOPOLOGY: standalone VERSION: "9.0" - TOOLCHAIN_VERSION: 3.14t - TEST_NAME: default_sync + TOOLCHAIN_VERSION: pypy3.11 + TEST_NAME: default_async tags: - test-standard - server-9.0 - - python-3.14t + - python-pypy3.11 - standalone-noauth-nossl - - sync - - free-threaded - - name: test-standard-latest-python3.11-sync-noauth-ssl-replica-set-cov + - async + - pypy + - name: test-standard-latest-python3.12-async-noauth-ssl-replica-set-cov commands: - func: run server vars: @@ -4416,80 +4372,102 @@ tasks: TOPOLOGY: replica_set VERSION: latest COVERAGE: "1" - TOOLCHAIN_VERSION: "3.11" - TEST_NAME: default_sync + TOOLCHAIN_VERSION: "3.12" + TEST_NAME: default_async tags: - test-standard - server-latest - - python-3.11 + - python-3.12 - replica_set-noauth-ssl - - sync + - async - pr - - name: test-standard-latest-python3.14t-sync-noauth-ssl-replica-set-cov + - name: test-standard-latest-pypy3.11-async-noauth-ssl-replica-set commands: - func: run server vars: AUTH: noauth SSL: ssl - TOPOLOGY: replica_set + TOPOLOGY: replica_set + VERSION: latest + - func: run tests + vars: + AUTH: noauth + SSL: ssl + TOPOLOGY: replica_set + VERSION: latest + TOOLCHAIN_VERSION: pypy3.11 + TEST_NAME: default_async + tags: + - test-standard + - server-latest + - python-pypy3.11 + - replica_set-noauth-ssl + - async + - pypy + - name: test-standard-latest-python3.13-async-auth-ssl-sharded-cluster-cov + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster VERSION: latest COVERAGE: "1" - func: run tests vars: - AUTH: noauth + AUTH: auth SSL: ssl - TOPOLOGY: replica_set + TOPOLOGY: sharded_cluster VERSION: latest COVERAGE: "1" - TOOLCHAIN_VERSION: 3.14t - TEST_NAME: default_sync + TOOLCHAIN_VERSION: "3.13" + TEST_NAME: default_async tags: - test-standard - server-latest - - python-3.14t - - replica_set-noauth-ssl - - sync - - free-threaded + - python-3.13 + - sharded_cluster-auth-ssl + - async - pr - - name: test-standard-latest-python3.12-async-auth-ssl-sharded-cluster-cov + - name: test-standard-latest-python3.11-async-noauth-nossl-standalone-cov commands: - func: run server vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster + AUTH: noauth + SSL: nossl + TOPOLOGY: standalone VERSION: latest COVERAGE: "1" - func: run tests vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster + AUTH: noauth + SSL: nossl + TOPOLOGY: standalone VERSION: latest COVERAGE: "1" - TOOLCHAIN_VERSION: "3.12" + TOOLCHAIN_VERSION: "3.11" TEST_NAME: default_async tags: - test-standard - server-latest - - python-3.12 - - sharded_cluster-auth-ssl + - python-3.11 + - standalone-noauth-nossl - async - pr - - name: test-standard-latest-python3.14-async-auth-ssl-sharded-cluster-cov + - name: test-standard-latest-python3.14-async-noauth-nossl-standalone-cov commands: - func: run server vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster + AUTH: noauth + SSL: nossl + TOPOLOGY: standalone VERSION: latest COVERAGE: "1" - func: run tests vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster + AUTH: noauth + SSL: nossl + TOPOLOGY: standalone VERSION: latest COVERAGE: "1" TOOLCHAIN_VERSION: "3.14" @@ -4498,22 +4476,22 @@ tasks: - test-standard - server-latest - python-3.14 - - sharded_cluster-auth-ssl + - standalone-noauth-nossl - async - pr - - name: test-standard-rapid-python3.12-sync-auth-ssl-sharded-cluster + - name: test-standard-rapid-python3.12-sync-noauth-ssl-replica-set commands: - func: run server vars: - AUTH: auth + AUTH: noauth SSL: ssl - TOPOLOGY: sharded_cluster + TOPOLOGY: replica_set VERSION: rapid - func: run tests vars: - AUTH: auth + AUTH: noauth SSL: ssl - TOPOLOGY: sharded_cluster + TOPOLOGY: replica_set VERSION: rapid TOOLCHAIN_VERSION: "3.12" TEST_NAME: default_sync @@ -4521,9 +4499,32 @@ tasks: - test-standard - server-rapid - python-3.12 - - sharded_cluster-auth-ssl + - replica_set-noauth-ssl + - sync + - name: test-standard-rapid-pypy3.11-sync-noauth-ssl-replica-set + commands: + - func: run server + vars: + AUTH: noauth + SSL: ssl + TOPOLOGY: replica_set + VERSION: rapid + - func: run tests + vars: + AUTH: noauth + SSL: ssl + TOPOLOGY: replica_set + VERSION: rapid + TOOLCHAIN_VERSION: pypy3.11 + TEST_NAME: default_sync + tags: + - test-standard + - server-rapid + - python-pypy3.11 + - replica_set-noauth-ssl - sync - - name: test-standard-rapid-python3.14-sync-auth-ssl-sharded-cluster + - pypy + - name: test-standard-rapid-python3.13-sync-auth-ssl-sharded-cluster commands: - func: run server vars: @@ -4537,15 +4538,15 @@ tasks: SSL: ssl TOPOLOGY: sharded_cluster VERSION: rapid - TOOLCHAIN_VERSION: "3.14" + TOOLCHAIN_VERSION: "3.13" TEST_NAME: default_sync tags: - test-standard - server-rapid - - python-3.14 + - python-3.13 - sharded_cluster-auth-ssl - sync - - name: test-standard-rapid-python3.11-async-noauth-nossl-standalone + - name: test-standard-rapid-python3.11-sync-noauth-nossl-standalone commands: - func: run server vars: @@ -4560,14 +4561,14 @@ tasks: TOPOLOGY: standalone VERSION: rapid TOOLCHAIN_VERSION: "3.11" - TEST_NAME: default_async + TEST_NAME: default_sync tags: - test-standard - server-rapid - python-3.11 - standalone-noauth-nossl - - async - - name: test-standard-rapid-python3.14t-async-noauth-nossl-standalone + - sync + - name: test-standard-rapid-python3.14-sync-noauth-nossl-standalone commands: - func: run server vars: @@ -4581,428 +4582,341 @@ tasks: SSL: nossl TOPOLOGY: standalone VERSION: rapid - TOOLCHAIN_VERSION: 3.14t - TEST_NAME: default_async + TOOLCHAIN_VERSION: "3.14" + TEST_NAME: default_sync tags: - test-standard - server-rapid - - python-3.14t + - python-3.14 - standalone-noauth-nossl - - async - - free-threaded + - sync # Test non standard tests - - name: test-non-standard-v4.2-python3.11-noauth-ssl-replica-set + - name: test-non-standard-v4.4-python3.11-noauth-ssl-replica-set commands: - func: run server vars: AUTH: noauth SSL: ssl TOPOLOGY: replica_set - VERSION: "4.2" + VERSION: "4.4" - func: run tests vars: AUTH: noauth SSL: ssl TOPOLOGY: replica_set - VERSION: "4.2" + VERSION: "4.4" TOOLCHAIN_VERSION: "3.11" tags: - test-non-standard - - server-4.2 + - server-4.4 - python-3.11 - replica_set-noauth-ssl - noauth - - name: test-non-standard-v4.2-python3.12-auth-ssl-sharded-cluster + - name: test-non-standard-v4.4-python3.12-auth-ssl-sharded-cluster commands: - func: run server vars: AUTH: auth SSL: ssl TOPOLOGY: sharded_cluster - VERSION: "4.2" + VERSION: "4.4" - func: run tests vars: AUTH: auth SSL: ssl TOPOLOGY: sharded_cluster - VERSION: "4.2" + VERSION: "4.4" TOOLCHAIN_VERSION: "3.12" tags: - test-non-standard - - server-4.2 + - server-4.4 - python-3.12 - sharded_cluster-auth-ssl - auth - - name: test-non-standard-v4.2-python3.10-noauth-nossl-standalone-min-deps + - name: test-non-standard-v4.4-python3.10-noauth-nossl-standalone-min-deps commands: - func: run server vars: AUTH: noauth SSL: nossl TOPOLOGY: standalone - VERSION: "4.2" + VERSION: "4.4" TEST_MIN_DEPS: "1" - func: run tests vars: AUTH: noauth SSL: nossl TOPOLOGY: standalone - VERSION: "4.2" + VERSION: "4.4" TEST_MIN_DEPS: "1" TOOLCHAIN_VERSION: "3.10" tags: - test-non-standard - - server-4.2 + - server-4.4 - python-3.10 - standalone-noauth-nossl - noauth - - name: test-non-standard-v4.2-pypy3.11-noauth-nossl-standalone + - name: test-non-standard-v4.4-pypy3.11-noauth-nossl-standalone commands: - func: run server vars: AUTH: noauth SSL: nossl TOPOLOGY: standalone - VERSION: "4.2" + VERSION: "4.4" - func: run tests vars: AUTH: noauth SSL: nossl TOPOLOGY: standalone - VERSION: "4.2" + VERSION: "4.4" TOOLCHAIN_VERSION: pypy3.11 tags: - test-non-standard - - server-4.2 + - server-4.4 - python-pypy3.11 - standalone-noauth-nossl - noauth - pypy - - name: test-non-standard-v4.4-python3.14t-noauth-ssl-replica-set + - name: test-non-standard-v5.0-python3.14t-noauth-ssl-replica-set commands: - func: run server vars: AUTH: noauth SSL: ssl TOPOLOGY: replica_set - VERSION: "4.4" + VERSION: "5.0" - func: run tests vars: AUTH: noauth SSL: ssl TOPOLOGY: replica_set - VERSION: "4.4" + VERSION: "5.0" TOOLCHAIN_VERSION: 3.14t tags: - test-non-standard - - server-4.4 + - server-5.0 - python-3.14t - replica_set-noauth-ssl - noauth - free-threaded - - name: test-non-standard-v4.4-pypy3.11-noauth-ssl-replica-set + - name: test-non-standard-v5.0-pypy3.11-noauth-ssl-replica-set commands: - func: run server vars: AUTH: noauth SSL: ssl TOPOLOGY: replica_set - VERSION: "4.4" + VERSION: "5.0" - func: run tests vars: AUTH: noauth SSL: ssl TOPOLOGY: replica_set - VERSION: "4.4" + VERSION: "5.0" TOOLCHAIN_VERSION: pypy3.11 tags: - test-non-standard - - server-4.4 + - server-5.0 - python-pypy3.11 - replica_set-noauth-ssl - noauth - pypy - - name: test-non-standard-v4.4-python3.14-auth-ssl-sharded-cluster + - name: test-non-standard-v5.0-python3.14-auth-ssl-sharded-cluster commands: - func: run server vars: AUTH: auth SSL: ssl TOPOLOGY: sharded_cluster - VERSION: "4.4" + VERSION: "5.0" - func: run tests vars: AUTH: auth SSL: ssl TOPOLOGY: sharded_cluster - VERSION: "4.4" + VERSION: "5.0" TOOLCHAIN_VERSION: "3.14" tags: - test-non-standard - - server-4.4 + - server-5.0 - python-3.14 - sharded_cluster-auth-ssl - auth - - name: test-non-standard-v4.4-python3.13-noauth-nossl-standalone + - name: test-non-standard-v5.0-python3.13-noauth-nossl-standalone commands: - func: run server vars: AUTH: noauth SSL: nossl TOPOLOGY: standalone - VERSION: "4.4" + VERSION: "5.0" - func: run tests vars: AUTH: noauth SSL: nossl TOPOLOGY: standalone - VERSION: "4.4" + VERSION: "5.0" TOOLCHAIN_VERSION: "3.13" tags: - test-non-standard - - server-4.4 + - server-5.0 - python-3.13 - standalone-noauth-nossl - noauth - - name: test-non-standard-v5.0-python3.11-noauth-ssl-replica-set + - name: test-non-standard-v6.0-python3.11-noauth-ssl-replica-set commands: - func: run server vars: AUTH: noauth SSL: ssl TOPOLOGY: replica_set - VERSION: "5.0" + VERSION: "6.0" - func: run tests vars: AUTH: noauth SSL: ssl TOPOLOGY: replica_set - VERSION: "5.0" + VERSION: "6.0" TOOLCHAIN_VERSION: "3.11" tags: - test-non-standard - - server-5.0 + - server-6.0 - python-3.11 - replica_set-noauth-ssl - noauth - - name: test-non-standard-v5.0-python3.12-auth-ssl-sharded-cluster + - name: test-non-standard-v6.0-python3.12-auth-ssl-sharded-cluster commands: - func: run server vars: AUTH: auth SSL: ssl TOPOLOGY: sharded_cluster - VERSION: "5.0" + VERSION: "6.0" - func: run tests vars: AUTH: auth SSL: ssl TOPOLOGY: sharded_cluster - VERSION: "5.0" + VERSION: "6.0" TOOLCHAIN_VERSION: "3.12" tags: - test-non-standard - - server-5.0 + - server-6.0 - python-3.12 - sharded_cluster-auth-ssl - auth - - name: test-non-standard-v5.0-pypy3.11-auth-ssl-sharded-cluster + - name: test-non-standard-v6.0-pypy3.11-auth-ssl-sharded-cluster commands: - func: run server vars: AUTH: auth SSL: ssl TOPOLOGY: sharded_cluster - VERSION: "5.0" + VERSION: "6.0" - func: run tests vars: AUTH: auth SSL: ssl TOPOLOGY: sharded_cluster - VERSION: "5.0" + VERSION: "6.0" TOOLCHAIN_VERSION: pypy3.11 tags: - test-non-standard - - server-5.0 + - server-6.0 - python-pypy3.11 - sharded_cluster-auth-ssl - auth - pypy - - name: test-non-standard-v5.0-python3.10-noauth-nossl-standalone-min-deps + - name: test-non-standard-v6.0-python3.10-noauth-nossl-standalone-min-deps commands: - func: run server vars: AUTH: noauth SSL: nossl TOPOLOGY: standalone - VERSION: "5.0" + VERSION: "6.0" TEST_MIN_DEPS: "1" - func: run tests vars: AUTH: noauth SSL: nossl TOPOLOGY: standalone - VERSION: "5.0" + VERSION: "6.0" TEST_MIN_DEPS: "1" TOOLCHAIN_VERSION: "3.10" tags: - test-non-standard - - server-5.0 + - server-6.0 - python-3.10 - standalone-noauth-nossl - noauth - - name: test-non-standard-v6.0-python3.14t-noauth-ssl-replica-set + - name: test-non-standard-v7.0-python3.14t-noauth-ssl-replica-set commands: - func: run server vars: AUTH: noauth SSL: ssl TOPOLOGY: replica_set - VERSION: "6.0" + VERSION: "7.0" - func: run tests vars: AUTH: noauth SSL: ssl TOPOLOGY: replica_set - VERSION: "6.0" + VERSION: "7.0" TOOLCHAIN_VERSION: 3.14t tags: - test-non-standard - - server-6.0 + - server-7.0 - python-3.14t - replica_set-noauth-ssl - noauth - free-threaded - - name: test-non-standard-v6.0-python3.14-auth-ssl-sharded-cluster + - name: test-non-standard-v7.0-python3.14-auth-ssl-sharded-cluster commands: - func: run server vars: AUTH: auth SSL: ssl TOPOLOGY: sharded_cluster - VERSION: "6.0" + VERSION: "7.0" - func: run tests vars: AUTH: auth SSL: ssl TOPOLOGY: sharded_cluster - VERSION: "6.0" + VERSION: "7.0" TOOLCHAIN_VERSION: "3.14" tags: - test-non-standard - - server-6.0 + - server-7.0 - python-3.14 - sharded_cluster-auth-ssl - auth - - name: test-non-standard-v6.0-python3.13-noauth-nossl-standalone - commands: - - func: run server - vars: - AUTH: noauth - SSL: nossl - TOPOLOGY: standalone - VERSION: "6.0" - - func: run tests - vars: - AUTH: noauth - SSL: nossl - TOPOLOGY: standalone - VERSION: "6.0" - TOOLCHAIN_VERSION: "3.13" - tags: - - test-non-standard - - server-6.0 - - python-3.13 - - standalone-noauth-nossl - - noauth - - name: test-non-standard-v6.0-pypy3.11-noauth-nossl-standalone + - name: test-non-standard-v7.0-python3.13-noauth-nossl-standalone commands: - func: run server vars: AUTH: noauth SSL: nossl TOPOLOGY: standalone - VERSION: "6.0" + VERSION: "7.0" - func: run tests vars: AUTH: noauth SSL: nossl TOPOLOGY: standalone - VERSION: "6.0" - TOOLCHAIN_VERSION: pypy3.11 - tags: - - test-non-standard - - server-6.0 - - python-pypy3.11 - - standalone-noauth-nossl - - noauth - - pypy - - name: test-non-standard-v7.0-python3.11-noauth-ssl-replica-set - commands: - - func: run server - vars: - AUTH: noauth - SSL: ssl - TOPOLOGY: replica_set - VERSION: "7.0" - - func: run tests - vars: - AUTH: noauth - SSL: ssl - TOPOLOGY: replica_set - VERSION: "7.0" - TOOLCHAIN_VERSION: "3.11" - tags: - - test-non-standard - - server-7.0 - - python-3.11 - - replica_set-noauth-ssl - - noauth - - name: test-non-standard-v7.0-pypy3.11-noauth-ssl-replica-set - commands: - - func: run server - vars: - AUTH: noauth - SSL: ssl - TOPOLOGY: replica_set - VERSION: "7.0" - - func: run tests - vars: - AUTH: noauth - SSL: ssl - TOPOLOGY: replica_set - VERSION: "7.0" - TOOLCHAIN_VERSION: pypy3.11 - tags: - - test-non-standard - - server-7.0 - - python-pypy3.11 - - replica_set-noauth-ssl - - noauth - - pypy - - name: test-non-standard-v7.0-python3.12-auth-ssl-sharded-cluster - commands: - - func: run server - vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster VERSION: "7.0" - - func: run tests - vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster - VERSION: "7.0" - TOOLCHAIN_VERSION: "3.12" + TOOLCHAIN_VERSION: "3.13" tags: - test-non-standard - server-7.0 - - python-3.12 - - sharded_cluster-auth-ssl - - auth - - name: test-non-standard-v7.0-python3.10-noauth-nossl-standalone-min-deps + - python-3.13 + - standalone-noauth-nossl + - noauth + - name: test-non-standard-v7.0-pypy3.11-noauth-nossl-standalone commands: - func: run server vars: @@ -5010,22 +4924,21 @@ tasks: SSL: nossl TOPOLOGY: standalone VERSION: "7.0" - TEST_MIN_DEPS: "1" - func: run tests vars: AUTH: noauth SSL: nossl TOPOLOGY: standalone VERSION: "7.0" - TEST_MIN_DEPS: "1" - TOOLCHAIN_VERSION: "3.10" + TOOLCHAIN_VERSION: pypy3.11 tags: - test-non-standard - server-7.0 - - python-3.10 + - python-pypy3.11 - standalone-noauth-nossl - noauth - - name: test-non-standard-v8.0-python3.14t-noauth-ssl-replica-set + - pypy + - name: test-non-standard-v8.0-python3.11-noauth-ssl-replica-set commands: - func: run server vars: @@ -5039,36 +4952,36 @@ tasks: SSL: ssl TOPOLOGY: replica_set VERSION: "8.0" - TOOLCHAIN_VERSION: 3.14t + TOOLCHAIN_VERSION: "3.11" tags: - test-non-standard - server-8.0 - - python-3.14t + - python-3.11 - replica_set-noauth-ssl - noauth - - free-threaded - - name: test-non-standard-v8.0-python3.14-auth-ssl-sharded-cluster + - name: test-non-standard-v8.0-pypy3.11-noauth-ssl-replica-set commands: - func: run server vars: - AUTH: auth + AUTH: noauth SSL: ssl - TOPOLOGY: sharded_cluster + TOPOLOGY: replica_set VERSION: "8.0" - func: run tests vars: - AUTH: auth + AUTH: noauth SSL: ssl - TOPOLOGY: sharded_cluster + TOPOLOGY: replica_set VERSION: "8.0" - TOOLCHAIN_VERSION: "3.14" + TOOLCHAIN_VERSION: pypy3.11 tags: - test-non-standard - server-8.0 - - python-3.14 - - sharded_cluster-auth-ssl - - auth - - name: test-non-standard-v8.0-pypy3.11-auth-ssl-sharded-cluster + - python-pypy3.11 + - replica_set-noauth-ssl + - noauth + - pypy + - name: test-non-standard-v8.0-python3.12-auth-ssl-sharded-cluster commands: - func: run server vars: @@ -5082,15 +4995,14 @@ tasks: SSL: ssl TOPOLOGY: sharded_cluster VERSION: "8.0" - TOOLCHAIN_VERSION: pypy3.11 + TOOLCHAIN_VERSION: "3.12" tags: - test-non-standard - server-8.0 - - python-pypy3.11 + - python-3.12 - sharded_cluster-auth-ssl - auth - - pypy - - name: test-non-standard-v8.0-python3.13-noauth-nossl-standalone + - name: test-non-standard-v8.0-python3.10-noauth-nossl-standalone-min-deps commands: - func: run server vars: @@ -5098,20 +5010,22 @@ tasks: SSL: nossl TOPOLOGY: standalone VERSION: "8.0" + TEST_MIN_DEPS: "1" - func: run tests vars: AUTH: noauth SSL: nossl TOPOLOGY: standalone VERSION: "8.0" - TOOLCHAIN_VERSION: "3.13" + TEST_MIN_DEPS: "1" + TOOLCHAIN_VERSION: "3.10" tags: - test-non-standard - server-8.0 - - python-3.13 + - python-3.10 - standalone-noauth-nossl - noauth - - name: test-non-standard-v9.0-python3.11-noauth-ssl-replica-set + - name: test-non-standard-v9.0-python3.14t-noauth-ssl-replica-set commands: - func: run server vars: @@ -5125,14 +5039,15 @@ tasks: SSL: ssl TOPOLOGY: replica_set VERSION: "9.0" - TOOLCHAIN_VERSION: "3.11" + TOOLCHAIN_VERSION: 3.14t tags: - test-non-standard - server-9.0 - - python-3.11 + - python-3.14t - replica_set-noauth-ssl - noauth - - name: test-non-standard-v9.0-python3.12-auth-ssl-sharded-cluster + - free-threaded + - name: test-non-standard-v9.0-python3.14-auth-ssl-sharded-cluster commands: - func: run server vars: @@ -5146,37 +5061,36 @@ tasks: SSL: ssl TOPOLOGY: sharded_cluster VERSION: "9.0" - TOOLCHAIN_VERSION: "3.12" + TOOLCHAIN_VERSION: "3.14" tags: - test-non-standard - server-9.0 - - python-3.12 + - python-3.14 - sharded_cluster-auth-ssl - auth - - name: test-non-standard-v9.0-python3.10-noauth-nossl-standalone-min-deps + - name: test-non-standard-v9.0-pypy3.11-auth-ssl-sharded-cluster commands: - func: run server vars: - AUTH: noauth - SSL: nossl - TOPOLOGY: standalone + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster VERSION: "9.0" - TEST_MIN_DEPS: "1" - func: run tests vars: - AUTH: noauth - SSL: nossl - TOPOLOGY: standalone + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster VERSION: "9.0" - TEST_MIN_DEPS: "1" - TOOLCHAIN_VERSION: "3.10" + TOOLCHAIN_VERSION: pypy3.11 tags: - test-non-standard - server-9.0 - - python-3.10 - - standalone-noauth-nossl - - noauth - - name: test-non-standard-v9.0-pypy3.11-noauth-nossl-standalone + - python-pypy3.11 + - sharded_cluster-auth-ssl + - auth + - pypy + - name: test-non-standard-v9.0-python3.13-noauth-nossl-standalone commands: - func: run server vars: @@ -5190,15 +5104,14 @@ tasks: SSL: nossl TOPOLOGY: standalone VERSION: "9.0" - TOOLCHAIN_VERSION: pypy3.11 + TOOLCHAIN_VERSION: "3.13" tags: - test-non-standard - server-9.0 - - python-pypy3.11 + - python-3.13 - standalone-noauth-nossl - noauth - - pypy - - name: test-non-standard-latest-python3.11-noauth-ssl-replica-set + - name: test-non-standard-latest-python3.14t-noauth-ssl-replica-set commands: - func: run server vars: @@ -5212,39 +5125,37 @@ tasks: SSL: ssl TOPOLOGY: replica_set VERSION: latest - TOOLCHAIN_VERSION: "3.11" + TOOLCHAIN_VERSION: 3.14t tags: - test-non-standard - server-latest - - python-3.11 + - python-3.14t - replica_set-noauth-ssl - noauth - - name: test-non-standard-latest-python3.12-auth-ssl-sharded-cluster-cov + - free-threaded + - name: test-non-standard-latest-pypy3.11-noauth-ssl-replica-set commands: - func: run server vars: - AUTH: auth + AUTH: noauth SSL: ssl - TOPOLOGY: sharded_cluster + TOPOLOGY: replica_set VERSION: latest - COVERAGE: "1" - func: run tests vars: - AUTH: auth + AUTH: noauth SSL: ssl - TOPOLOGY: sharded_cluster + TOPOLOGY: replica_set VERSION: latest - COVERAGE: "1" - TOOLCHAIN_VERSION: "3.12" + TOOLCHAIN_VERSION: pypy3.11 tags: - test-non-standard - server-latest - - python-3.12 - - sharded_cluster-auth-ssl - - auth - - pr - - cov - - name: test-non-standard-latest-python3.12-auth-ssl-sharded-cluster + - python-pypy3.11 + - replica_set-noauth-ssl + - noauth + - pypy + - name: test-non-standard-latest-python3.14-auth-ssl-sharded-cluster-cov commands: - func: run server vars: @@ -5252,21 +5163,24 @@ tasks: SSL: ssl TOPOLOGY: sharded_cluster VERSION: latest + COVERAGE: "1" - func: run tests vars: AUTH: auth SSL: ssl TOPOLOGY: sharded_cluster VERSION: latest - TOOLCHAIN_VERSION: "3.12" + COVERAGE: "1" + TOOLCHAIN_VERSION: "3.14" tags: - - test-non-standard-no-cov + - test-non-standard - server-latest - - python-3.12 + - python-3.14 - sharded_cluster-auth-ssl - auth - pr - - name: test-non-standard-latest-pypy3.11-auth-ssl-sharded-cluster + - cov + - name: test-non-standard-latest-python3.14-auth-ssl-sharded-cluster commands: - func: run server vars: @@ -5280,15 +5194,15 @@ tasks: SSL: ssl TOPOLOGY: sharded_cluster VERSION: latest - TOOLCHAIN_VERSION: pypy3.11 + TOOLCHAIN_VERSION: "3.14" tags: - - test-non-standard + - test-non-standard-no-cov - server-latest - - python-pypy3.11 + - python-3.14 - sharded_cluster-auth-ssl - auth - - pypy - - name: test-non-standard-latest-python3.10-noauth-nossl-standalone-min-deps + - pr + - name: test-non-standard-latest-python3.13-noauth-nossl-standalone commands: - func: run server vars: @@ -5296,22 +5210,20 @@ tasks: SSL: nossl TOPOLOGY: standalone VERSION: latest - TEST_MIN_DEPS: "1" - func: run tests vars: AUTH: noauth SSL: nossl TOPOLOGY: standalone VERSION: latest - TEST_MIN_DEPS: "1" - TOOLCHAIN_VERSION: "3.10" + TOOLCHAIN_VERSION: "3.13" tags: - test-non-standard - server-latest - - python-3.10 + - python-3.13 - standalone-noauth-nossl - noauth - - name: test-non-standard-rapid-python3.14t-noauth-ssl-replica-set + - name: test-non-standard-rapid-python3.11-noauth-ssl-replica-set commands: - func: run server vars: @@ -5325,58 +5237,58 @@ tasks: SSL: ssl TOPOLOGY: replica_set VERSION: rapid - TOOLCHAIN_VERSION: 3.14t + TOOLCHAIN_VERSION: "3.11" tags: - test-non-standard - server-rapid - - python-3.14t + - python-3.11 - replica_set-noauth-ssl - noauth - - free-threaded - - name: test-non-standard-rapid-pypy3.11-noauth-ssl-replica-set + - name: test-non-standard-rapid-python3.12-auth-ssl-sharded-cluster commands: - func: run server vars: - AUTH: noauth + AUTH: auth SSL: ssl - TOPOLOGY: replica_set + TOPOLOGY: sharded_cluster VERSION: rapid - func: run tests vars: - AUTH: noauth + AUTH: auth SSL: ssl - TOPOLOGY: replica_set + TOPOLOGY: sharded_cluster VERSION: rapid - TOOLCHAIN_VERSION: pypy3.11 + TOOLCHAIN_VERSION: "3.12" tags: - test-non-standard - server-rapid - - python-pypy3.11 - - replica_set-noauth-ssl - - noauth - - pypy - - name: test-non-standard-rapid-python3.14-auth-ssl-sharded-cluster + - python-3.12 + - sharded_cluster-auth-ssl + - auth + - name: test-non-standard-rapid-python3.10-noauth-nossl-standalone-min-deps commands: - func: run server vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster + AUTH: noauth + SSL: nossl + TOPOLOGY: standalone VERSION: rapid + TEST_MIN_DEPS: "1" - func: run tests vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster + AUTH: noauth + SSL: nossl + TOPOLOGY: standalone VERSION: rapid - TOOLCHAIN_VERSION: "3.14" + TEST_MIN_DEPS: "1" + TOOLCHAIN_VERSION: "3.10" tags: - test-non-standard - server-rapid - - python-3.14 - - sharded_cluster-auth-ssl - - auth - - name: test-non-standard-rapid-python3.13-noauth-nossl-standalone + - python-3.10 + - standalone-noauth-nossl + - noauth + - name: test-non-standard-rapid-pypy3.11-noauth-nossl-standalone commands: - func: run server vars: @@ -5390,13 +5302,14 @@ tasks: SSL: nossl TOPOLOGY: standalone VERSION: rapid - TOOLCHAIN_VERSION: "3.13" + TOOLCHAIN_VERSION: pypy3.11 tags: - test-non-standard - server-rapid - - python-3.13 + - python-pypy3.11 - standalone-noauth-nossl - noauth + - pypy # Test numpy tests - name: test-numpy-python3.10-python3.10 @@ -5423,70 +5336,27 @@ tasks: - pr # Test standard auth tests - - name: test-standard-auth-v4.2-python3.10-auth-ssl-sharded-cluster-min-deps + - name: test-standard-auth-v4.4-python3.10-auth-ssl-sharded-cluster-min-deps commands: - func: run server vars: AUTH: auth SSL: ssl TOPOLOGY: sharded_cluster - VERSION: "4.2" + VERSION: "4.4" TEST_MIN_DEPS: "1" - func: run tests vars: AUTH: auth SSL: ssl TOPOLOGY: sharded_cluster - VERSION: "4.2" + VERSION: "4.4" TEST_MIN_DEPS: "1" TOOLCHAIN_VERSION: "3.10" - tags: - - test-standard-auth - - server-4.2 - - python-3.10 - - sharded_cluster-auth-ssl - - auth - - name: test-standard-auth-v4.2-pypy3.11-auth-ssl-sharded-cluster - commands: - - func: run server - vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster - VERSION: "4.2" - - func: run tests - vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster - VERSION: "4.2" - TOOLCHAIN_VERSION: pypy3.11 - tags: - - test-standard-auth - - server-4.2 - - python-pypy3.11 - - sharded_cluster-auth-ssl - - auth - - pypy - - name: test-standard-auth-v4.4-python3.11-auth-ssl-sharded-cluster - commands: - - func: run server - vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster - VERSION: "4.4" - - func: run tests - vars: - AUTH: auth - SSL: ssl - TOPOLOGY: sharded_cluster - VERSION: "4.4" - TOOLCHAIN_VERSION: "3.11" tags: - test-standard-auth - server-4.4 - - python-3.11 + - python-3.10 - sharded_cluster-auth-ssl - auth - name: test-standard-auth-v4.4-pypy3.11-auth-ssl-sharded-cluster @@ -5511,7 +5381,7 @@ tasks: - sharded_cluster-auth-ssl - auth - pypy - - name: test-standard-auth-v5.0-python3.12-auth-ssl-sharded-cluster + - name: test-standard-auth-v5.0-python3.11-auth-ssl-sharded-cluster commands: - func: run server vars: @@ -5525,11 +5395,11 @@ tasks: SSL: ssl TOPOLOGY: sharded_cluster VERSION: "5.0" - TOOLCHAIN_VERSION: "3.12" + TOOLCHAIN_VERSION: "3.11" tags: - test-standard-auth - server-5.0 - - python-3.12 + - python-3.11 - sharded_cluster-auth-ssl - auth - name: test-standard-auth-v5.0-pypy3.11-auth-ssl-sharded-cluster @@ -5554,7 +5424,7 @@ tasks: - sharded_cluster-auth-ssl - auth - pypy - - name: test-standard-auth-v6.0-python3.13-auth-ssl-sharded-cluster + - name: test-standard-auth-v6.0-python3.12-auth-ssl-sharded-cluster commands: - func: run server vars: @@ -5568,11 +5438,11 @@ tasks: SSL: ssl TOPOLOGY: sharded_cluster VERSION: "6.0" - TOOLCHAIN_VERSION: "3.13" + TOOLCHAIN_VERSION: "3.12" tags: - test-standard-auth - server-6.0 - - python-3.13 + - python-3.12 - sharded_cluster-auth-ssl - auth - name: test-standard-auth-v6.0-pypy3.11-auth-ssl-sharded-cluster @@ -5597,7 +5467,7 @@ tasks: - sharded_cluster-auth-ssl - auth - pypy - - name: test-standard-auth-v7.0-python3.14t-auth-ssl-sharded-cluster + - name: test-standard-auth-v7.0-python3.13-auth-ssl-sharded-cluster commands: - func: run server vars: @@ -5611,14 +5481,13 @@ tasks: SSL: ssl TOPOLOGY: sharded_cluster VERSION: "7.0" - TOOLCHAIN_VERSION: 3.14t + TOOLCHAIN_VERSION: "3.13" tags: - test-standard-auth - server-7.0 - - python-3.14t + - python-3.13 - sharded_cluster-auth-ssl - auth - - free-threaded - name: test-standard-auth-v7.0-pypy3.11-auth-ssl-sharded-cluster commands: - func: run server @@ -5641,7 +5510,7 @@ tasks: - sharded_cluster-auth-ssl - auth - pypy - - name: test-standard-auth-v8.0-python3.14-auth-ssl-sharded-cluster + - name: test-standard-auth-v8.0-python3.14t-auth-ssl-sharded-cluster commands: - func: run server vars: @@ -5655,13 +5524,14 @@ tasks: SSL: ssl TOPOLOGY: sharded_cluster VERSION: "8.0" - TOOLCHAIN_VERSION: "3.14" + TOOLCHAIN_VERSION: 3.14t tags: - test-standard-auth - server-8.0 - - python-3.14 + - python-3.14t - sharded_cluster-auth-ssl - auth + - free-threaded - name: test-standard-auth-v8.0-pypy3.11-auth-ssl-sharded-cluster commands: - func: run server @@ -5684,7 +5554,7 @@ tasks: - sharded_cluster-auth-ssl - auth - pypy - - name: test-standard-auth-v9.0-python3.10-auth-ssl-sharded-cluster-min-deps + - name: test-standard-auth-v9.0-python3.14-auth-ssl-sharded-cluster commands: - func: run server vars: @@ -5692,19 +5562,17 @@ tasks: SSL: ssl TOPOLOGY: sharded_cluster VERSION: "9.0" - TEST_MIN_DEPS: "1" - func: run tests vars: AUTH: auth SSL: ssl TOPOLOGY: sharded_cluster VERSION: "9.0" - TEST_MIN_DEPS: "1" - TOOLCHAIN_VERSION: "3.10" + TOOLCHAIN_VERSION: "3.14" tags: - test-standard-auth - server-9.0 - - python-3.10 + - python-3.14 - sharded_cluster-auth-ssl - auth - name: test-standard-auth-v9.0-pypy3.11-auth-ssl-sharded-cluster @@ -5729,7 +5597,7 @@ tasks: - sharded_cluster-auth-ssl - auth - pypy - - name: test-standard-auth-latest-python3.12-auth-ssl-sharded-cluster-cov + - name: test-standard-auth-latest-python3.11-auth-ssl-sharded-cluster-cov commands: - func: run server vars: @@ -5745,11 +5613,11 @@ tasks: TOPOLOGY: sharded_cluster VERSION: latest COVERAGE: "1" - TOOLCHAIN_VERSION: "3.12" + TOOLCHAIN_VERSION: "3.11" tags: - test-standard-auth - server-latest - - python-3.12 + - python-3.11 - sharded_cluster-auth-ssl - auth - pr @@ -5775,7 +5643,7 @@ tasks: - sharded_cluster-auth-ssl - auth - pypy - - name: test-standard-auth-rapid-python3.11-auth-ssl-sharded-cluster + - name: test-standard-auth-rapid-python3.10-auth-ssl-sharded-cluster-min-deps commands: - func: run server vars: @@ -5783,17 +5651,19 @@ tasks: SSL: ssl TOPOLOGY: sharded_cluster VERSION: rapid + TEST_MIN_DEPS: "1" - func: run tests vars: AUTH: auth SSL: ssl TOPOLOGY: sharded_cluster VERSION: rapid - TOOLCHAIN_VERSION: "3.11" + TEST_MIN_DEPS: "1" + TOOLCHAIN_VERSION: "3.10" tags: - test-standard-auth - server-rapid - - python-3.11 + - python-3.10 - sharded_cluster-auth-ssl - auth - name: test-standard-auth-rapid-pypy3.11-auth-ssl-sharded-cluster diff --git a/.evergreen/generated_configs/variants.yml b/.evergreen/generated_configs/variants.yml index dfa03da69f..32955ba2d7 100644 --- a/.evergreen/generated_configs/variants.yml +++ b/.evergreen/generated_configs/variants.yml @@ -134,7 +134,7 @@ buildvariants: COMPRESSOR: zlib - name: compression-zstd-rhel8 tasks: - - name: .test-standard !.server-4.2 + - name: .test-standard display_name: Compression zstd RHEL8 run_on: - rhel87-small @@ -142,8 +142,8 @@ buildvariants: COMPRESSOR: zstd - name: compression-zstd-ubuntu-22 tasks: - - name: .test-standard !.server-4.2 !.server-4.4 !.server-5.0 .python-3.14 - - name: .test-standard !.server-4.2 !.server-4.4 !.server-5.0 .python-3.14t + - name: .test-standard !.server-4.4 !.server-5.0 .python-3.14 + - name: .test-standard !.server-4.4 !.server-5.0 .python-3.14t display_name: Compression zstd Ubuntu-22 run_on: - ubuntu2204-small @@ -492,15 +492,6 @@ buildvariants: - rhel87-small # Server version tests - - name: mongodb-v4.2 - tasks: - - name: .server-version - display_name: "* MongoDB v4.2" - run_on: - - rhel87-small - expansions: - VERSION: "4.2" - tags: [coverage_tag] - name: mongodb-v4.4 tasks: - name: .server-version diff --git a/.evergreen/scripts/generate_config.py b/.evergreen/scripts/generate_config.py index 3318625a25..0b4c45740f 100644 --- a/.evergreen/scripts/generate_config.py +++ b/.evergreen/scripts/generate_config.py @@ -187,10 +187,7 @@ def create_compression_variants(): variants = [] for compressor in "snappy", "zlib", "zstd": expansions = dict(COMPRESSOR=compressor) - if compressor == "zstd": - tasks = [".test-standard !.server-4.2"] - else: - tasks = [".test-standard"] + tasks = [".test-standard"] display_name = get_variant_name(f"Compression {compressor}", host) variants.append( create_variant( @@ -204,8 +201,8 @@ def create_compression_variants(): host = HOSTS["ubuntu22"] expansions = dict(COMPRESSOR="ztsd") tasks = [ - ".test-standard !.server-4.2 !.server-4.4 !.server-5.0 .python-3.14", - ".test-standard !.server-4.2 !.server-4.4 !.server-5.0 .python-3.14t", + ".test-standard !.server-4.4 !.server-5.0 .python-3.14", + ".test-standard !.server-4.4 !.server-5.0 .python-3.14t", ] display_name = get_variant_name(f"Compression {compressor}", host) variants.append( diff --git a/.evergreen/scripts/generate_config_utils.py b/.evergreen/scripts/generate_config_utils.py index 634c947d20..296d4e2416 100644 --- a/.evergreen/scripts/generate_config_utils.py +++ b/.evergreen/scripts/generate_config_utils.py @@ -21,7 +21,7 @@ # Globals ############## -ALL_VERSIONS = ["4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "9.0", "rapid", "latest"] +ALL_VERSIONS = ["4.4", "5.0", "6.0", "7.0", "8.0", "9.0", "rapid", "latest"] CPYTHONS = ["3.10", "3.11", "3.12", "3.13", "3.14t", "3.14"] PYPYS = ["pypy3.11"] MIN_SUPPORT_VERSIONS = ["3.9", "pypy3.9", "pypy3.10"] diff --git a/.evergreen/scripts/install-dependencies.sh b/.evergreen/scripts/install-dependencies.sh index 8df2af79ca..7f943d7d00 100755 --- a/.evergreen/scripts/install-dependencies.sh +++ b/.evergreen/scripts/install-dependencies.sh @@ -3,6 +3,7 @@ set -eu HERE=$(dirname ${BASH_SOURCE:-$0}) +HERE="$( cd -- "$HERE" > /dev/null 2>&1 && pwd )" pushd "$(dirname "$(dirname $HERE)")" > /dev/null # Source the env files to pick up common variables. diff --git a/.evergreen/scripts/setup-dev-env.sh b/.evergreen/scripts/setup-dev-env.sh index 83b1b622b4..e58d6210fe 100755 --- a/.evergreen/scripts/setup-dev-env.sh +++ b/.evergreen/scripts/setup-dev-env.sh @@ -22,6 +22,12 @@ fi # 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. +if [ -f $HERE/env.sh ]; then + . $HERE/env.sh +fi + # Add the default install path to the path if needed. if [ -z "${PYMONGO_BIN_DIR:-}" ]; then export PATH="$PATH:$HOME/.local/bin" diff --git a/.evergreen/scripts/setup-uv-python.sh b/.evergreen/scripts/setup-uv-python.sh index a32e4a8f92..e83abce4b9 100755 --- a/.evergreen/scripts/setup-uv-python.sh +++ b/.evergreen/scripts/setup-uv-python.sh @@ -41,9 +41,16 @@ if [ -z "${UV_PYTHON:-}" ]; then _exe="python.exe" fi if [ -n "${IS_WIN32:-}" ]; then - _python="C:/python/32/Python${_python}/${_exe}" + _win_python="C:/python/32/Python${_python}/${_exe}" else - _python="C:/python/Python${_python}/${_exe}" + _win_python="C:/python/Python${_python}/${_exe}" + fi + # Fall back to the version string if the toolchain path doesn't exist. + # uv will then download and manage Python itself. + if [ -f "$_win_python" ]; then + _python="$_win_python" + else + _python="$TOOLCHAIN_VERSION" fi elif [ -d "/opt/python/$_python/bin" ]; then _python="/opt/python/$_python/bin/python3" diff --git a/.evergreen/scripts/setup_tests.py b/.evergreen/scripts/setup_tests.py index 1a41b3a8b0..b5c40b9c5a 100644 --- a/.evergreen/scripts/setup_tests.py +++ b/.evergreen/scripts/setup_tests.py @@ -273,6 +273,7 @@ def handle_test_env() -> None: write_env("GSSAPI_HOST", config["SASL_HOST"]) write_env("GSSAPI_PORT", config["SASL_PORT"]) write_env("GSSAPI_PRINCIPAL", config["PRINCIPAL"]) + write_env("SASL_HOST", config["SASL_HOST"]) if test_name == "doctest": UV_ARGS.append("--extra docs") diff --git a/README.md b/README.md index 6e029dc164..babf0fc79b 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ a native Python driver for MongoDB, offering both synchronous and asynchronous A [gridfs](https://github.com/mongodb/specifications/blob/master/source/gridfs/gridfs-spec.md/) implementation on top of `pymongo`. -PyMongo supports MongoDB 4.0, 4.2, 4.4, 5.0, 6.0, 7.0, and 8.0. PyMongo follows [semantic versioning](https://semver.org/spec/v2.0.0.html) for its releases. +PyMongo supports MongoDB 4.4, 5.0, 6.0, 7.0, 8.0, and 9.0. PyMongo follows [semantic versioning](https://semver.org/spec/v2.0.0.html) for its releases. ## Documentation diff --git a/doc/changelog.rst b/doc/changelog.rst index e752f9bcb2..064982d29c 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -6,6 +6,7 @@ Changes in Version 4.18.0 (2026/XX/XX) PyMongo 4.18 brings a number of changes including: +- Dropped support for MongoDB 4.2. - Added support for MongoDB 9.0. - Improved TLS connection performance by reusing TLS sessions across connections to the same server, avoiding a full handshake on each new connection. diff --git a/pymongo/asynchronous/aggregation.py b/pymongo/asynchronous/aggregation.py index 5f70e84fef..8d21ecf46f 100644 --- a/pymongo/asynchronous/aggregation.py +++ b/pymongo/asynchronous/aggregation.py @@ -53,7 +53,7 @@ def __init__( options: MutableMapping[str, Any], let: Optional[Mapping[str, Any]] = None, user_fields: Optional[MutableMapping[str, Any]] = None, - result_processor: Optional[Callable[[Mapping[str, Any], AsyncConnection], None]] = None, + result_processor: Optional[Callable[[Mapping[str, Any]], None]] = None, comment: Any = None, ) -> None: if "explain" in options: @@ -145,13 +145,8 @@ async def get_cursor( cmd = {"aggregate": self._aggregation_target, "pipeline": self._pipeline} cmd.update(self._options) - # Apply this target's read concern if: - # readConcern has not been specified as a kwarg and either - # - server version is >= 4.2 or - # - server version is >= 3.2 and pipeline doesn't use $out - if ("readConcern" not in cmd) and ( - not self._performs_write or (conn.max_wire_version >= 8) - ): + # $out/$merge pipelines also support readConcern on all supported server versions (4.4+). + if "readConcern" not in cmd: read_concern = self._target.read_concern else: read_concern = None @@ -180,7 +175,7 @@ async def get_cursor( ) if self._result_processor: - self._result_processor(result, conn) + self._result_processor(result) # Extract cursor from result or mock/fake one if necessary. if "cursor" in result: diff --git a/pymongo/asynchronous/auth.py b/pymongo/asynchronous/auth.py index cd3cee6295..d1b0a8f68c 100644 --- a/pymongo/asynchronous/auth.py +++ b/pymongo/asynchronous/auth.py @@ -343,20 +343,17 @@ async def _authenticate_x509(credentials: MongoCredential, conn: AsyncConnection async def _authenticate_default(credentials: MongoCredential, conn: AsyncConnection) -> None: - if conn.max_wire_version >= 7: - if conn.negotiated_mechs: - mechs = conn.negotiated_mechs - else: - source = credentials.source - cmd = conn.hello_cmd() - cmd["saslSupportedMechs"] = source + "." + credentials.username - mechs = (await conn.command(source, cmd, publish_events=False)).get( - "saslSupportedMechs", [] - ) - if "SCRAM-SHA-256" in mechs: - return await _authenticate_scram(credentials, conn, "SCRAM-SHA-256") - else: - return await _authenticate_scram(credentials, conn, "SCRAM-SHA-1") + if conn.negotiated_mechs: + mechs = conn.negotiated_mechs + else: + source = credentials.source + cmd = conn.hello_cmd() + cmd["saslSupportedMechs"] = source + "." + credentials.username + mechs = (await conn.command(source, cmd, publish_events=False)).get( + "saslSupportedMechs", [] + ) + if "SCRAM-SHA-256" in mechs: + return await _authenticate_scram(credentials, conn, "SCRAM-SHA-256") else: return await _authenticate_scram(credentials, conn, "SCRAM-SHA-1") diff --git a/pymongo/asynchronous/auth_aws.py b/pymongo/asynchronous/auth_aws.py index 5fb8ec7e07..7982936948 100644 --- a/pymongo/asynchronous/auth_aws.py +++ b/pymongo/asynchronous/auth_aws.py @@ -48,9 +48,6 @@ async def _authenticate_aws(credentials: MongoCredential, conn: AsyncConnection) set_use_cached_credentials(True) - if conn.max_wire_version < 9: - raise ConfigurationError("MONGODB-AWS authentication requires MongoDB version 4.4 or later") - class AwsSaslContext(pymongo_auth_aws.AwsSaslContext): # type: ignore # Dependency injection: def binary_type(self) -> type[Binary]: diff --git a/pymongo/asynchronous/bulk.py b/pymongo/asynchronous/bulk.py index ef28d77c1b..622b3cf2b7 100644 --- a/pymongo/asynchronous/bulk.py +++ b/pymongo/asynchronous/bulk.py @@ -102,8 +102,6 @@ def __init__( self.bypass_doc_val = bypass_document_validation self.uses_collation = False self.uses_array_filters = False - self.uses_hint_update = False - self.uses_hint_delete = False self.uses_sort = False self.is_retryable = True self.retrying = False @@ -154,7 +152,6 @@ def add_update( self.uses_array_filters = True cmd["arrayFilters"] = array_filters if hint is not None: - self.uses_hint_update = True cmd["hint"] = hint if sort is not None: self.uses_sort = True @@ -182,7 +179,6 @@ def add_replace( self.uses_collation = True cmd["collation"] = collation if hint is not None: - self.uses_hint_update = True cmd["hint"] = hint if sort is not None: self.uses_sort = True @@ -202,7 +198,6 @@ def add_delete( self.uses_collation = True cmd["collation"] = collation if hint is not None: - self.uses_hint_delete = True cmd["hint"] = hint if limit == _DELETE_ALL: # A bulk_write containing a delete_many is not retryable. @@ -572,14 +567,6 @@ async def execute_no_results( raise ConfigurationError("arrayFilters is unsupported for unacknowledged writes.") # Guard against unsupported unacknowledged writes. unack = write_concern and not write_concern.acknowledged - if unack and self.uses_hint_delete and conn.max_wire_version < 9: - raise ConfigurationError( - "Must be connected to MongoDB 4.4+ to use hint on unacknowledged delete commands." - ) - if unack and self.uses_hint_update and conn.max_wire_version < 8: - raise ConfigurationError( - "Must be connected to MongoDB 4.2+ to use hint on unacknowledged update commands." - ) if unack and self.uses_sort and conn.max_wire_version < 25: raise ConfigurationError( "Must be connected to MongoDB 8.0+ to use sort on unacknowledged update commands." diff --git a/pymongo/asynchronous/change_stream.py b/pymongo/asynchronous/change_stream.py index e9d588ac95..33f79814b1 100644 --- a/pymongo/asynchronous/change_stream.py +++ b/pymongo/asynchronous/change_stream.py @@ -43,37 +43,11 @@ _IS_SYNC = False -# The change streams spec considers the following server errors from the -# getMore command non-resumable. All other getMore errors are resumable. -_RESUMABLE_GETMORE_ERRORS = frozenset( - [ - 6, # HostUnreachable - 7, # HostNotFound - 89, # NetworkTimeout - 91, # ShutdownInProgress - 189, # PrimarySteppedDown - 262, # ExceededTimeLimit - 9001, # SocketException - 10107, # NotWritablePrimary - 11600, # InterruptedAtShutdown - 11602, # InterruptedDueToReplStateChange - 13435, # NotPrimaryNoSecondaryOk - 13436, # NotPrimaryOrSecondary - 63, # StaleShardVersion - 150, # StaleEpoch - 13388, # StaleConfig - 234, # RetryChangeStream - 133, # FailedToSatisfyReadPreference - ] -) - - if TYPE_CHECKING: from pymongo.asynchronous.client_session import AsyncClientSession from pymongo.asynchronous.collection import AsyncCollection from pymongo.asynchronous.database import AsyncDatabase from pymongo.asynchronous.mongo_client import AsyncMongoClient - from pymongo.asynchronous.pool import AsyncConnection def _resumable(exc: PyMongoError) -> bool: @@ -81,11 +55,7 @@ def _resumable(exc: PyMongoError) -> bool: if isinstance(exc, (ConnectionFailure, CursorNotFound)): return True if isinstance(exc, OperationFailure): - if exc._max_wire_version is None: - return False - return ( - exc._max_wire_version >= 9 and exc.has_error_label("ResumableChangeStreamError") - ) or (exc._max_wire_version < 9 and exc.code in _RESUMABLE_GETMORE_ERRORS) + return exc.has_error_label("ResumableChangeStreamError") return False @@ -212,13 +182,10 @@ def _aggregation_pipeline(self) -> list[dict[str, Any]]: full_pipeline.extend(self._pipeline) return full_pipeline - def _process_result(self, result: Mapping[str, Any], conn: AsyncConnection) -> None: + def _process_result(self, result: Mapping[str, Any]) -> None: """Callback that caches the postBatchResumeToken or startAtOperationTime from a changeStream aggregate command response containing an empty batch of change documents. - - This is implemented as a callback because we need access to the wire - version in order to determine whether to cache this value. """ if not result["cursor"]["firstBatch"]: if "postBatchResumeToken" in result["cursor"]: @@ -227,7 +194,6 @@ def _process_result(self, result: Mapping[str, Any], conn: AsyncConnection) -> N self._start_at_operation_time is None and self._uses_resume_after is False and self._uses_start_after is False - and conn.max_wire_version >= 7 ): self._start_at_operation_time = result.get("operationTime") # PYTHON-2181: informative error on missing operationTime. diff --git a/pymongo/asynchronous/collection.py b/pymongo/asynchronous/collection.py index ff2df1be82..1595828260 100644 --- a/pymongo/asynchronous/collection.py +++ b/pymongo/asynchronous/collection.py @@ -1010,10 +1010,6 @@ async def _update( else: update_doc["arrayFilters"] = array_filters if hint is not None: - if not acknowledged and conn.max_wire_version < 8: - raise ConfigurationError( - "Must be connected to MongoDB 4.2+ to use hint on unacknowledged update commands." - ) if not isinstance(hint, str): hint = helpers_shared._index_document(hint) update_doc["hint"] = hint @@ -1170,8 +1166,7 @@ async def replace_one( predicate specified either by its string name, or in the same format as passed to :meth:`~pymongo.asynchronous.collection.AsyncCollection.create_index` (e.g. - ``[('field', ASCENDING)]``). This option is only supported on - MongoDB 4.2 and above. + ``[('field', ASCENDING)]``). :param session: a :class:`~pymongo.asynchronous.client_session.AsyncClientSession`. :param let: Map of parameter names and values. Values must be @@ -1286,8 +1281,7 @@ async def update_one( predicate specified either by its string name, or in the same format as passed to :meth:`~pymongo.asynchronous.collection.AsyncCollection.create_index` (e.g. - ``[('field', ASCENDING)]``). This option is only supported on - MongoDB 4.2 and above. + ``[('field', ASCENDING)]``). :param session: a :class:`~pymongo.asynchronous.client_session.AsyncClientSession`. :param let: Map of parameter names and values. Values must be @@ -1392,8 +1386,7 @@ async def update_many( predicate specified either by its string name, or in the same format as passed to :meth:`~pymongo.asynchronous.collection.AsyncCollection.create_index` (e.g. - ``[('field', ASCENDING)]``). This option is only supported on - MongoDB 4.2 and above. + ``[('field', ASCENDING)]``). :param session: a :class:`~pymongo.asynchronous.client_session.AsyncClientSession`. :param let: Map of parameter names and values. Values must be @@ -1515,10 +1508,6 @@ async def _delete( else: delete_doc["collation"] = collation if hint is not None: - if not acknowledged and conn.max_wire_version < 9: - raise ConfigurationError( - "Must be connected to MongoDB 4.4+ to use hint on unacknowledged delete commands." - ) if not isinstance(hint, str): hint = helpers_shared._index_document(hint) delete_doc["hint"] = hint @@ -2248,8 +2237,6 @@ async def _create_indexes( async def inner( session: Optional[AsyncClientSession], conn: AsyncConnection, _retryable_write: bool ) -> list[str]: - supports_quorum = conn.max_wire_version >= 9 - def gen_indexes() -> Iterator[Mapping[str, Any]]: for index in indexes: if not isinstance(index, IndexModel): @@ -2262,12 +2249,6 @@ def gen_indexes() -> Iterator[Mapping[str, Any]]: cmd = {"createIndexes": self.name, "indexes": list(gen_indexes())} cmd.update(kwargs) - if "commitQuorum" in kwargs and not supports_quorum: - raise ConfigurationError( - "Must be connected to MongoDB 4.4+ to use the " - "commitQuorum option for createIndexes" - ) - await self._command( conn, cmd, @@ -2343,7 +2324,7 @@ async def create_index( :class:`~pymongo.collation.Collation`. - `wildcardProjection`: Allows users to include or exclude specific field paths from a `wildcard index`_ using the {"$**" : 1} key - pattern. Requires MongoDB >= 4.2. + pattern. - `hidden`: if ``True``, this index will be hidden from the query planner and will not be evaluated as part of query plan selection. Requires MongoDB >= 4.4. @@ -3307,14 +3288,6 @@ async def _find_and_modify_helper( ) cmd["arrayFilters"] = list(array_filters) if hint is not None: - if conn.max_wire_version < 8: - raise ConfigurationError( - "Must be connected to MongoDB 4.2+ to use hint on find and modify commands." - ) - elif not acknowledged and conn.max_wire_version < 9: - raise ConfigurationError( - "Must be connected to MongoDB 4.4+ to use hint on unacknowledged find and modify commands." - ) cmd["hint"] = hint out = await self._command( conn, diff --git a/pymongo/asynchronous/cursor.py b/pymongo/asynchronous/cursor.py index 1b2428a6d8..362b4a9739 100644 --- a/pymongo/asynchronous/cursor.py +++ b/pymongo/asynchronous/cursor.py @@ -635,9 +635,8 @@ def max_scan(self, max_scan: Optional[int]) -> AsyncCursor[_DocumentType]: def max(self, spec: _Sort) -> AsyncCursor[_DocumentType]: """Adds ``max`` operator that specifies upper bound for specific index. - When using ``max``, :meth:`~hint` should also be configured to ensure - the query uses the expected index and starting in MongoDB 4.2 - :meth:`~hint` will be required. + When using ``max``, :meth:`~hint` is required to ensure the query + uses the expected index. :param spec: a list of field, limit pairs specifying the exclusive upper bound for all keys of a specific index in order. @@ -657,9 +656,8 @@ def max(self, spec: _Sort) -> AsyncCursor[_DocumentType]: def min(self, spec: _Sort) -> AsyncCursor[_DocumentType]: """Adds ``min`` operator that specifies lower bound for specific index. - When using ``min``, :meth:`~hint` should also be configured to ensure - the query uses the expected index and starting in MongoDB 4.2 - :meth:`~hint` will be required. + When using ``min``, :meth:`~hint` is required to ensure the query + uses the expected index. :param spec: a list of field, limit pairs specifying the inclusive lower bound for all keys of a specific index in order. diff --git a/pymongo/asynchronous/cursor_base.py b/pymongo/asynchronous/cursor_base.py index e8ac4c3139..0f07769f20 100644 --- a/pymongo/asynchronous/cursor_base.py +++ b/pymongo/asynchronous/cursor_base.py @@ -116,7 +116,7 @@ async def _run_with_conn( if more_to_come: request_id, data, max_doc_size = 0, b"", 0 else: - message = operation.get_message(read_preference, conn, use_cmd) + message = operation.get_message(read_preference, conn) request_id, data, max_doc_size = _split_message(message) user_fields = _CURSOR_DOC_FIELDS if use_cmd else None docs, reply, duration = await run_cursor_command( @@ -154,7 +154,6 @@ async def _run_with_conn( conn=conn, duration=duration, request_id=request_id, - from_command=use_cmd, docs=docs, # type: ignore[arg-type] more_to_come=more_to_come, ) @@ -163,7 +162,6 @@ async def _run_with_conn( address=conn.address, duration=duration, request_id=request_id, - from_command=use_cmd, docs=docs, # type: ignore[arg-type] ) diff --git a/pymongo/asynchronous/mongo_client.py b/pymongo/asynchronous/mongo_client.py index db5c790d64..baa281b59a 100644 --- a/pymongo/asynchronous/mongo_client.py +++ b/pymongo/asynchronous/mongo_client.py @@ -81,7 +81,6 @@ PyMongoError, ServerSelectionTimeoutError, WaitQueueTimeoutError, - WriteConcernError, ) from pymongo.lock import ( _HAS_REGISTER_AT_FORK, @@ -421,8 +420,7 @@ def __init__( zlib support requires the Python standard library zlib module. For Python before 3.14 zstd requires the `backports.zstd `_ package. By default no compression is used. Compression support - must also be enabled on the server. MongoDB 3.6+ supports snappy - and zlib compression. MongoDB 4.2+ adds support for zstd. + must also be enabled on the server. See `compress network traffic `_ for details. - `zlibCompressionLevel`: (int) The zlib compression level to use when zlib is used as the wire protocol compressor. Supported values @@ -2585,7 +2583,7 @@ def _retryable_error_doc(exc: PyMongoError) -> Optional[Mapping[str, Any]]: return None -def _add_retryable_write_error(exc: PyMongoError, max_wire_version: int, is_mongos: bool) -> None: +def _add_retryable_write_error(exc: PyMongoError) -> None: doc = _retryable_error_doc(exc) if doc: code = doc.get("code", 0) @@ -2597,16 +2595,8 @@ def _add_retryable_write_error(exc: PyMongoError, max_wire_version: int, is_mong "to your connection string." ) raise OperationFailure(errmsg, code, exc.details) # type: ignore[attr-defined] - if max_wire_version >= 9: - # In MongoDB 4.4+, the server reports the error labels. - for label in doc.get("errorLabels", []): - exc._add_error_label(label) - else: - # Do not consult writeConcernError for pre-4.4 mongos. - if isinstance(exc, WriteConcernError) and is_mongos: - pass - elif code in helpers_shared._RETRYABLE_ERROR_CODES: - exc._add_error_label("RetryableWriteError") + for label in doc.get("errorLabels", []): + exc._add_error_label(label) # AsyncConnection errors are always retryable except NotPrimaryError and WaitQueueTimeoutError which is # handled above. @@ -2735,14 +2725,6 @@ async def __aenter__(self) -> AsyncConnection: ): session._pin(server, conn) self.contribute_socket(conn) - if ( - self.client._encrypter - and not self.client._encrypter._bypass_auto_encryption - and conn.max_wire_version < 8 - ): - raise ConfigurationError( - "Auto-encryption requires a minimum MongoDB version of 4.2" - ) except BaseException as exc: try: await self.handle(type(exc), exc) @@ -3111,17 +3093,13 @@ async def _write(self) -> T: :return: Output for func()'s call """ try: - max_wire_version = 0 - is_mongos = False self._server = await self._get_server() async with self._client._checkout(self._server, self._session) as conn: - max_wire_version = conn.max_wire_version sessions_supported = ( self._session and self._server.description.retryable_writes_supported and conn.supports_sessions ) - is_mongos = conn.is_mongos if not self._always_retryable and not sessions_supported: # A retry is not possible because this server does # not support sessions raise the last error. @@ -3138,7 +3116,7 @@ async def _write(self) -> T: if not self._retryable: raise # Add the RetryableWriteError label, if applicable. - _add_retryable_write_error(exc, max_wire_version, is_mongos) + _add_retryable_write_error(exc) raise async def _read(self) -> T: diff --git a/pymongo/asynchronous/pool.py b/pymongo/asynchronous/pool.py index a126962e4a..eb9cb215eb 100644 --- a/pymongo/asynchronous/pool.py +++ b/pymongo/asynchronous/pool.py @@ -226,7 +226,7 @@ async def unpin(self) -> None: def hello_cmd(self) -> dict[str, Any]: # As of PYTHON-5713, always use OP_MSG for the handshake since all - # supported servers (MongoDB 4.2+, wire version >= 8) support it. + # supported servers (MongoDB 4.4+, wire version >= 9) support it. if self.opts.server_api or self.hello_ok or self.opts.load_balanced: return {HelloCompat.CMD: 1} return {HelloCompat.LEGACY_CMD: 1, "helloOk": True} diff --git a/pymongo/asynchronous/topology.py b/pymongo/asynchronous/topology.py index 1ed36151d2..72481296ff 100644 --- a/pymongo/asynchronous/topology.py +++ b/pymongo/asynchronous/topology.py @@ -764,8 +764,7 @@ async def _handle_error(self, address: _Address, err_ctx: _ErrorContext) -> None elif isinstance(error, (NotPrimaryError, OperationFailure)): # As per the SDAM spec if: # - the server sees a "not primary" error, and - # - the server is not shutting down, and - # - the server version is >= 4.2, then + # - the server is not shutting down, then # we keep the existing connection pool, but mark the server type # as Unknown and request an immediate check of the server. # Otherwise, we clear the connection pool, mark the server as @@ -778,10 +777,9 @@ async def _handle_error(self, address: _Address, err_ctx: _ErrorContext) -> None err_code = error.details.get("code", default) # type: ignore[union-attr] if err_code in helpers_shared._NOT_PRIMARY_CODES: is_shutting_down = err_code in helpers_shared._SHUTDOWN_CODES - # Mark server Unknown, clear the pool, and request check. if not self._settings.load_balanced: await self._process_change(ServerDescription(address, error=error)) - if is_shutting_down or (err_ctx.max_wire_version <= 7): + if is_shutting_down: # Clear the pool. await server.reset(service_id) server.request_check() diff --git a/pymongo/common.py b/pymongo/common.py index 174d99c512..096cb26513 100644 --- a/pymongo/common.py +++ b/pymongo/common.py @@ -64,8 +64,8 @@ MAX_WRITE_BATCH_SIZE = 100000 # What this version of PyMongo supports. -MIN_SUPPORTED_SERVER_VERSION = "4.2" -MIN_SUPPORTED_WIRE_VERSION = 8 +MIN_SUPPORTED_SERVER_VERSION = "4.4" +MIN_SUPPORTED_WIRE_VERSION = 9 # MongoDB 9.0 MAX_SUPPORTED_WIRE_VERSION = 29 diff --git a/pymongo/encryption_options.py b/pymongo/encryption_options.py index f2fcd47c65..e410ef6846 100644 --- a/pymongo/encryption_options.py +++ b/pymongo/encryption_options.py @@ -77,13 +77,13 @@ def __init__( ) -> None: """Options to configure automatic client-side field level encryption. - Automatic client-side field level encryption requires MongoDB >=4.2 - enterprise or a MongoDB >=4.2 Atlas cluster. Automatic encryption is not + Automatic client-side field level encryption requires MongoDB + enterprise or a MongoDB Atlas cluster. Automatic encryption is not supported for operations on a database or view and will result in error. - Although automatic encryption requires MongoDB >=4.2 enterprise or a - MongoDB >=4.2 Atlas cluster, automatic *decryption* is supported for all + Although automatic encryption requires MongoDB enterprise or a + MongoDB Atlas cluster, automatic *decryption* is supported for all users. To configure automatic *decryption* without automatic *encryption* set ``bypass_auto_encryption=True``. Explicit encryption and explicit decryption is also supported for all users diff --git a/pymongo/message.py b/pymongo/message.py index b696ba2302..df7d940532 100644 --- a/pymongo/message.py +++ b/pymongo/message.py @@ -229,7 +229,6 @@ def _gen_get_more_command( batch_size: Optional[int], max_await_time_ms: Optional[int], comment: Optional[Any], - conn: _AgnosticConnection, ) -> dict[str, Any]: """Generate a getMore command document.""" cmd: dict[str, Any] = {"getMore": cursor_id, "collection": coll} @@ -237,7 +236,7 @@ def _gen_get_more_command( cmd["batchSize"] = batch_size if max_await_time_ms is not None: cmd["maxTimeMS"] = max_await_time_ms - if comment is not None and conn.max_wire_version >= 9: + if comment is not None: cmd["comment"] = comment return cmd @@ -378,54 +377,6 @@ def _op_msg( command[identifier] = docs -_pack_long_long = struct.Struct(" bytes: - """Get an OP_GET_MORE message.""" - return b"".join( - [ - _ZERO_32, - bson._make_c_string(collection_name), - _pack_int(num_to_return), - _pack_long_long(cursor_id), - ] - ) - - -def _get_more_compressed( - collection_name: str, - num_to_return: int, - cursor_id: int, - ctx: Union[SnappyContext, ZlibContext, ZstdContext], -) -> tuple[int, bytes]: - """Internal compressed getMore message helper.""" - return _compress(2005, _get_more_impl(collection_name, num_to_return, cursor_id), ctx) - - -def _get_more_uncompressed( - collection_name: str, num_to_return: int, cursor_id: int -) -> tuple[int, bytes]: - """Internal getMore message helper.""" - return __pack_message(2005, _get_more_impl(collection_name, num_to_return, cursor_id)) - - -if _use_c: - _get_more_uncompressed = _cmessage._get_more_message - - -def _get_more( - collection_name: str, - num_to_return: int, - cursor_id: int, - ctx: Union[SnappyContext, ZlibContext, ZstdContext, None] = None, -) -> tuple[int, bytes]: - """Get a **getMore** message.""" - if ctx: - return _get_more_compressed(collection_name, num_to_return, cursor_id, ctx) - return _get_more_uncompressed(collection_name, num_to_return, cursor_id) - - # OP_MSG ------------------------------------------------------------- @@ -1353,7 +1304,7 @@ def as_command( return self._as_command def get_message( - self, read_preference: _ServerMode, conn: _AgnosticConnection, use_cmd: bool = False + self, read_preference: _ServerMode, conn: _AgnosticConnection ) -> tuple[int, bytes, int]: """Get a query message""" # Use the read_preference decided by _socket_from_server. @@ -1451,7 +1402,6 @@ def as_command( self.ntoreturn, self.max_await_time_ms, self.comment, - conn, ) if self.session: self.session._apply_to(cmd, False, self.read_preference, conn) # type: ignore[arg-type] @@ -1463,49 +1413,22 @@ def as_command( self._as_command = cmd, self.db return self._as_command - def get_message( - self, dummy0: Any, conn: _AgnosticConnection, use_cmd: bool = False - ) -> Union[tuple[int, bytes, int], tuple[int, bytes]]: + def get_message(self, dummy0: Any, conn: _AgnosticConnection) -> tuple[int, bytes, int]: """Get a getmore message.""" - ns = self.namespace() - ctx = conn.compression_context - - if use_cmd: - spec = self.as_command(conn)[0] - if self.conn_mgr and self.exhaust: - flags = _OpMsg.EXHAUST_ALLOWED - else: - flags = 0 - request_id, msg, size, _ = _op_msg( - flags, spec, self.db, None, self.codec_options, ctx=conn.compression_context - ) - return request_id, msg, size - - return _get_more(ns, self.ntoreturn, self.cursor_id, ctx) + spec = self.as_command(conn)[0] + flags = _OpMsg.EXHAUST_ALLOWED if (self.conn_mgr and self.exhaust) else 0 + request_id, msg, size, _ = _op_msg( + flags, spec, self.db, None, self.codec_options, ctx=conn.compression_context + ) + return request_id, msg, size class _RawBatchQuery(_Query): - def use_command(self, conn: _AgnosticConnection) -> bool: - # Compatibility checks. - super().use_command(conn) - if conn.max_wire_version >= 8: - # MongoDB 4.2+ supports exhaust over OP_MSG - return True - elif not self.exhaust: - return True - return False + pass class _RawBatchGetMore(_GetMore): - def use_command(self, conn: _AgnosticConnection) -> bool: - # Compatibility checks. - super().use_command(conn) - if conn.max_wire_version >= 8: - # MongoDB 4.2+ supports exhaust over OP_MSG - return True - elif not self.exhaust: - return True - return False + pass class _CursorAddress(tuple[Any, ...]): diff --git a/pymongo/operations.py b/pymongo/operations.py index b664a289ba..99b6a00c52 100644 --- a/pymongo/operations.py +++ b/pymongo/operations.py @@ -366,8 +366,7 @@ def __init__( predicate specified either by its string name, or in the same format as passed to :meth:`~pymongo.asynchronous.collection.AsyncCollection.create_index` or :meth:`~pymongo.collection.Collection.create_index` (e.g. - ``[('field', ASCENDING)]``). This option is only supported on - MongoDB 4.2 and above. + ``[('field', ASCENDING)]``). :param sort: Specify which document the operation updates if the query matches multiple documents. The first document matched by the sort order will be updated. :param namespace: (optional) The namespace in which to replace a document. @@ -566,8 +565,7 @@ def __init__( predicate specified either by its string name, or in the same format as passed to :meth:`~pymongo.asynchronous.collection.AsyncCollection.create_index` or :meth:`~pymongo.collection.Collection.create_index` (e.g. - ``[('field', ASCENDING)]``). This option is only supported on - MongoDB 4.2 and above. + ``[('field', ASCENDING)]``). :param namespace: The namespace in which to update a document. :param sort: Specify which document the operation updates if the query matches multiple documents. The first document matched by the sort order will be updated. @@ -651,8 +649,7 @@ def __init__( predicate specified either by its string name, or in the same format as passed to :meth:`~pymongo.asynchronous.collection.AsyncCollection.create_index` or :meth:`~pymongo.collection.Collection.create_index` (e.g. - ``[('field', ASCENDING)]``). This option is only supported on - MongoDB 4.2 and above. + ``[('field', ASCENDING)]``). :param namespace: (optional) The namespace in which to update documents. .. versionchanged:: 4.9 @@ -742,7 +739,7 @@ def __init__(self, keys: _IndexKeyHint, **kwargs: Any) -> None: that specifies the collation to use. - `wildcardProjection`: Allows users to include or exclude specific field paths from a `wildcard index`_ using the { "$**" : 1} key - pattern. Requires MongoDB >= 4.2. + pattern. - `hidden`: if ``True``, this index will be hidden from the query planner and will not be evaluated as part of query plan selection. Requires MongoDB >= 4.4. diff --git a/pymongo/response.py b/pymongo/response.py index 69cba81200..b832036708 100644 --- a/pymongo/response.py +++ b/pymongo/response.py @@ -27,7 +27,7 @@ class Response: - __slots__ = ("_address", "_data", "_docs", "_duration", "_from_command", "_request_id") + __slots__ = ("_address", "_data", "_docs", "_duration", "_request_id") def __init__( self, @@ -35,7 +35,6 @@ def __init__( address: _Address, request_id: int, duration: Optional[timedelta], - from_command: bool, docs: Sequence[Mapping[str, Any]], ): """Represent a response from the server. @@ -44,13 +43,11 @@ def __init__( :param address: (host, port) of the source server. :param request_id: The request id of this operation. :param duration: The duration of the operation. - :param from_command: if the response is the result of a db command. """ self._data = data self._address = address self._request_id = request_id self._duration = duration - self._from_command = from_command self._docs = docs @property @@ -73,11 +70,6 @@ def duration(self) -> Optional[timedelta]: """The duration of the operation.""" return self._duration - @property - def from_command(self) -> bool: - """If the response is a result from a db command.""" - return self._from_command - @property def docs(self) -> Sequence[Mapping[str, Any]]: """The decoded document(s).""" @@ -94,7 +86,6 @@ def __init__( conn: _AgnosticConnection, request_id: int, duration: Optional[timedelta], - from_command: bool, docs: list[_DocumentOut], more_to_come: bool, ): @@ -105,12 +96,11 @@ def __init__( :param conn: The AsyncConnection/Connection used for the initial query. :param request_id: The request id of this operation. :param duration: The duration of the operation. - :param from_command: If the response is the result of a db command. :param docs: List of documents. :param more_to_come: Bool indicating whether cursor is ready to be exhausted. """ - super().__init__(data, address, request_id, duration, from_command, docs) + super().__init__(data, address, request_id, duration, docs) self._conn = conn self._more_to_come = more_to_come diff --git a/pymongo/synchronous/aggregation.py b/pymongo/synchronous/aggregation.py index 7e13afa8ec..df49bbfbdd 100644 --- a/pymongo/synchronous/aggregation.py +++ b/pymongo/synchronous/aggregation.py @@ -53,7 +53,7 @@ def __init__( options: MutableMapping[str, Any], let: Optional[Mapping[str, Any]] = None, user_fields: Optional[MutableMapping[str, Any]] = None, - result_processor: Optional[Callable[[Mapping[str, Any], Connection], None]] = None, + result_processor: Optional[Callable[[Mapping[str, Any]], None]] = None, comment: Any = None, ) -> None: if "explain" in options: @@ -145,13 +145,8 @@ def get_cursor( cmd = {"aggregate": self._aggregation_target, "pipeline": self._pipeline} cmd.update(self._options) - # Apply this target's read concern if: - # readConcern has not been specified as a kwarg and either - # - server version is >= 4.2 or - # - server version is >= 3.2 and pipeline doesn't use $out - if ("readConcern" not in cmd) and ( - not self._performs_write or (conn.max_wire_version >= 8) - ): + # $out/$merge pipelines also support readConcern on all supported server versions (4.4+). + if "readConcern" not in cmd: read_concern = self._target.read_concern else: read_concern = None @@ -180,7 +175,7 @@ def get_cursor( ) if self._result_processor: - self._result_processor(result, conn) + self._result_processor(result) # Extract cursor from result or mock/fake one if necessary. if "cursor" in result: diff --git a/pymongo/synchronous/auth.py b/pymongo/synchronous/auth.py index 5bb5cb454f..18c4e62b57 100644 --- a/pymongo/synchronous/auth.py +++ b/pymongo/synchronous/auth.py @@ -341,18 +341,15 @@ def _authenticate_x509(credentials: MongoCredential, conn: Connection) -> None: def _authenticate_default(credentials: MongoCredential, conn: Connection) -> None: - if conn.max_wire_version >= 7: - if conn.negotiated_mechs: - mechs = conn.negotiated_mechs - else: - source = credentials.source - cmd = conn.hello_cmd() - cmd["saslSupportedMechs"] = source + "." + credentials.username - mechs = (conn.command(source, cmd, publish_events=False)).get("saslSupportedMechs", []) - if "SCRAM-SHA-256" in mechs: - return _authenticate_scram(credentials, conn, "SCRAM-SHA-256") - else: - return _authenticate_scram(credentials, conn, "SCRAM-SHA-1") + if conn.negotiated_mechs: + mechs = conn.negotiated_mechs + else: + source = credentials.source + cmd = conn.hello_cmd() + cmd["saslSupportedMechs"] = source + "." + credentials.username + mechs = (conn.command(source, cmd, publish_events=False)).get("saslSupportedMechs", []) + if "SCRAM-SHA-256" in mechs: + return _authenticate_scram(credentials, conn, "SCRAM-SHA-256") else: return _authenticate_scram(credentials, conn, "SCRAM-SHA-1") diff --git a/pymongo/synchronous/auth_aws.py b/pymongo/synchronous/auth_aws.py index b20f3c2110..777e0620f5 100644 --- a/pymongo/synchronous/auth_aws.py +++ b/pymongo/synchronous/auth_aws.py @@ -48,9 +48,6 @@ def _authenticate_aws(credentials: MongoCredential, conn: Connection) -> None: set_use_cached_credentials(True) - if conn.max_wire_version < 9: - raise ConfigurationError("MONGODB-AWS authentication requires MongoDB version 4.4 or later") - class AwsSaslContext(pymongo_auth_aws.AwsSaslContext): # type: ignore # Dependency injection: def binary_type(self) -> type[Binary]: diff --git a/pymongo/synchronous/bulk.py b/pymongo/synchronous/bulk.py index 9338a2e6a1..79d64c07c2 100644 --- a/pymongo/synchronous/bulk.py +++ b/pymongo/synchronous/bulk.py @@ -102,8 +102,6 @@ def __init__( self.bypass_doc_val = bypass_document_validation self.uses_collation = False self.uses_array_filters = False - self.uses_hint_update = False - self.uses_hint_delete = False self.uses_sort = False self.is_retryable = True self.retrying = False @@ -154,7 +152,6 @@ def add_update( self.uses_array_filters = True cmd["arrayFilters"] = array_filters if hint is not None: - self.uses_hint_update = True cmd["hint"] = hint if sort is not None: self.uses_sort = True @@ -182,7 +179,6 @@ def add_replace( self.uses_collation = True cmd["collation"] = collation if hint is not None: - self.uses_hint_update = True cmd["hint"] = hint if sort is not None: self.uses_sort = True @@ -202,7 +198,6 @@ def add_delete( self.uses_collation = True cmd["collation"] = collation if hint is not None: - self.uses_hint_delete = True cmd["hint"] = hint if limit == _DELETE_ALL: # A bulk_write containing a delete_many is not retryable. @@ -570,14 +565,6 @@ def execute_no_results( raise ConfigurationError("arrayFilters is unsupported for unacknowledged writes.") # Guard against unsupported unacknowledged writes. unack = write_concern and not write_concern.acknowledged - if unack and self.uses_hint_delete and conn.max_wire_version < 9: - raise ConfigurationError( - "Must be connected to MongoDB 4.4+ to use hint on unacknowledged delete commands." - ) - if unack and self.uses_hint_update and conn.max_wire_version < 8: - raise ConfigurationError( - "Must be connected to MongoDB 4.2+ to use hint on unacknowledged update commands." - ) if unack and self.uses_sort and conn.max_wire_version < 25: raise ConfigurationError( "Must be connected to MongoDB 8.0+ to use sort on unacknowledged update commands." diff --git a/pymongo/synchronous/change_stream.py b/pymongo/synchronous/change_stream.py index f442cc6c67..44a6dab2a3 100644 --- a/pymongo/synchronous/change_stream.py +++ b/pymongo/synchronous/change_stream.py @@ -43,37 +43,11 @@ _IS_SYNC = True -# The change streams spec considers the following server errors from the -# getMore command non-resumable. All other getMore errors are resumable. -_RESUMABLE_GETMORE_ERRORS = frozenset( - [ - 6, # HostUnreachable - 7, # HostNotFound - 89, # NetworkTimeout - 91, # ShutdownInProgress - 189, # PrimarySteppedDown - 262, # ExceededTimeLimit - 9001, # SocketException - 10107, # NotWritablePrimary - 11600, # InterruptedAtShutdown - 11602, # InterruptedDueToReplStateChange - 13435, # NotPrimaryNoSecondaryOk - 13436, # NotPrimaryOrSecondary - 63, # StaleShardVersion - 150, # StaleEpoch - 13388, # StaleConfig - 234, # RetryChangeStream - 133, # FailedToSatisfyReadPreference - ] -) - - if TYPE_CHECKING: from pymongo.synchronous.client_session import ClientSession from pymongo.synchronous.collection import Collection from pymongo.synchronous.database import Database from pymongo.synchronous.mongo_client import MongoClient - from pymongo.synchronous.pool import Connection def _resumable(exc: PyMongoError) -> bool: @@ -81,11 +55,7 @@ def _resumable(exc: PyMongoError) -> bool: if isinstance(exc, (ConnectionFailure, CursorNotFound)): return True if isinstance(exc, OperationFailure): - if exc._max_wire_version is None: - return False - return ( - exc._max_wire_version >= 9 and exc.has_error_label("ResumableChangeStreamError") - ) or (exc._max_wire_version < 9 and exc.code in _RESUMABLE_GETMORE_ERRORS) + return exc.has_error_label("ResumableChangeStreamError") return False @@ -212,13 +182,10 @@ def _aggregation_pipeline(self) -> list[dict[str, Any]]: full_pipeline.extend(self._pipeline) return full_pipeline - def _process_result(self, result: Mapping[str, Any], conn: Connection) -> None: + def _process_result(self, result: Mapping[str, Any]) -> None: """Callback that caches the postBatchResumeToken or startAtOperationTime from a changeStream aggregate command response containing an empty batch of change documents. - - This is implemented as a callback because we need access to the wire - version in order to determine whether to cache this value. """ if not result["cursor"]["firstBatch"]: if "postBatchResumeToken" in result["cursor"]: @@ -227,7 +194,6 @@ def _process_result(self, result: Mapping[str, Any], conn: Connection) -> None: self._start_at_operation_time is None and self._uses_resume_after is False and self._uses_start_after is False - and conn.max_wire_version >= 7 ): self._start_at_operation_time = result.get("operationTime") # PYTHON-2181: informative error on missing operationTime. diff --git a/pymongo/synchronous/collection.py b/pymongo/synchronous/collection.py index 3051ac9839..cf8cdb7842 100644 --- a/pymongo/synchronous/collection.py +++ b/pymongo/synchronous/collection.py @@ -1010,10 +1010,6 @@ def _update( else: update_doc["arrayFilters"] = array_filters if hint is not None: - if not acknowledged and conn.max_wire_version < 8: - raise ConfigurationError( - "Must be connected to MongoDB 4.2+ to use hint on unacknowledged update commands." - ) if not isinstance(hint, str): hint = helpers_shared._index_document(hint) update_doc["hint"] = hint @@ -1170,8 +1166,7 @@ def replace_one( predicate specified either by its string name, or in the same format as passed to :meth:`~pymongo.collection.Collection.create_index` (e.g. - ``[('field', ASCENDING)]``). This option is only supported on - MongoDB 4.2 and above. + ``[('field', ASCENDING)]``). :param session: a :class:`~pymongo.client_session.ClientSession`. :param let: Map of parameter names and values. Values must be @@ -1286,8 +1281,7 @@ def update_one( predicate specified either by its string name, or in the same format as passed to :meth:`~pymongo.collection.Collection.create_index` (e.g. - ``[('field', ASCENDING)]``). This option is only supported on - MongoDB 4.2 and above. + ``[('field', ASCENDING)]``). :param session: a :class:`~pymongo.client_session.ClientSession`. :param let: Map of parameter names and values. Values must be @@ -1392,8 +1386,7 @@ def update_many( predicate specified either by its string name, or in the same format as passed to :meth:`~pymongo.collection.Collection.create_index` (e.g. - ``[('field', ASCENDING)]``). This option is only supported on - MongoDB 4.2 and above. + ``[('field', ASCENDING)]``). :param session: a :class:`~pymongo.client_session.ClientSession`. :param let: Map of parameter names and values. Values must be @@ -1515,10 +1508,6 @@ def _delete( else: delete_doc["collation"] = collation if hint is not None: - if not acknowledged and conn.max_wire_version < 9: - raise ConfigurationError( - "Must be connected to MongoDB 4.4+ to use hint on unacknowledged delete commands." - ) if not isinstance(hint, str): hint = helpers_shared._index_document(hint) delete_doc["hint"] = hint @@ -2246,8 +2235,6 @@ def _create_indexes( def inner( session: Optional[ClientSession], conn: Connection, _retryable_write: bool ) -> list[str]: - supports_quorum = conn.max_wire_version >= 9 - def gen_indexes() -> Iterator[Mapping[str, Any]]: for index in indexes: if not isinstance(index, IndexModel): @@ -2260,12 +2247,6 @@ def gen_indexes() -> Iterator[Mapping[str, Any]]: cmd = {"createIndexes": self.name, "indexes": list(gen_indexes())} cmd.update(kwargs) - if "commitQuorum" in kwargs and not supports_quorum: - raise ConfigurationError( - "Must be connected to MongoDB 4.4+ to use the " - "commitQuorum option for createIndexes" - ) - self._command( conn, cmd, @@ -2339,7 +2320,7 @@ def create_index( :class:`~pymongo.collation.Collation`. - `wildcardProjection`: Allows users to include or exclude specific field paths from a `wildcard index`_ using the {"$**" : 1} key - pattern. Requires MongoDB >= 4.2. + pattern. - `hidden`: if ``True``, this index will be hidden from the query planner and will not be evaluated as part of query plan selection. Requires MongoDB >= 4.4. @@ -3301,14 +3282,6 @@ def _find_and_modify_helper( ) cmd["arrayFilters"] = list(array_filters) if hint is not None: - if conn.max_wire_version < 8: - raise ConfigurationError( - "Must be connected to MongoDB 4.2+ to use hint on find and modify commands." - ) - elif not acknowledged and conn.max_wire_version < 9: - raise ConfigurationError( - "Must be connected to MongoDB 4.4+ to use hint on unacknowledged find and modify commands." - ) cmd["hint"] = hint out = self._command( conn, diff --git a/pymongo/synchronous/cursor.py b/pymongo/synchronous/cursor.py index fddbcc520f..9d6908f35a 100644 --- a/pymongo/synchronous/cursor.py +++ b/pymongo/synchronous/cursor.py @@ -633,9 +633,8 @@ def max_scan(self, max_scan: Optional[int]) -> Cursor[_DocumentType]: def max(self, spec: _Sort) -> Cursor[_DocumentType]: """Adds ``max`` operator that specifies upper bound for specific index. - When using ``max``, :meth:`~hint` should also be configured to ensure - the query uses the expected index and starting in MongoDB 4.2 - :meth:`~hint` will be required. + When using ``max``, :meth:`~hint` is required to ensure the query + uses the expected index. :param spec: a list of field, limit pairs specifying the exclusive upper bound for all keys of a specific index in order. @@ -655,9 +654,8 @@ def max(self, spec: _Sort) -> Cursor[_DocumentType]: def min(self, spec: _Sort) -> Cursor[_DocumentType]: """Adds ``min`` operator that specifies lower bound for specific index. - When using ``min``, :meth:`~hint` should also be configured to ensure - the query uses the expected index and starting in MongoDB 4.2 - :meth:`~hint` will be required. + When using ``min``, :meth:`~hint` is required to ensure the query + uses the expected index. :param spec: a list of field, limit pairs specifying the inclusive lower bound for all keys of a specific index in order. diff --git a/pymongo/synchronous/cursor_base.py b/pymongo/synchronous/cursor_base.py index 4cad4e0c09..3a04fad681 100644 --- a/pymongo/synchronous/cursor_base.py +++ b/pymongo/synchronous/cursor_base.py @@ -116,7 +116,7 @@ def _run_with_conn( if more_to_come: request_id, data, max_doc_size = 0, b"", 0 else: - message = operation.get_message(read_preference, conn, use_cmd) + message = operation.get_message(read_preference, conn) request_id, data, max_doc_size = _split_message(message) user_fields = _CURSOR_DOC_FIELDS if use_cmd else None docs, reply, duration = run_cursor_command( @@ -154,7 +154,6 @@ def _run_with_conn( conn=conn, duration=duration, request_id=request_id, - from_command=use_cmd, docs=docs, # type: ignore[arg-type] more_to_come=more_to_come, ) @@ -163,7 +162,6 @@ def _run_with_conn( address=conn.address, duration=duration, request_id=request_id, - from_command=use_cmd, docs=docs, # type: ignore[arg-type] ) diff --git a/pymongo/synchronous/mongo_client.py b/pymongo/synchronous/mongo_client.py index 3959455d3f..c6b03201b6 100644 --- a/pymongo/synchronous/mongo_client.py +++ b/pymongo/synchronous/mongo_client.py @@ -71,7 +71,6 @@ PyMongoError, ServerSelectionTimeoutError, WaitQueueTimeoutError, - WriteConcernError, ) from pymongo.lock import ( _HAS_REGISTER_AT_FORK, @@ -422,8 +421,7 @@ def __init__( zlib support requires the Python standard library zlib module. For Python before 3.14 zstd requires the `backports.zstd `_ package. By default no compression is used. Compression support - must also be enabled on the server. MongoDB 3.6+ supports snappy - and zlib compression. MongoDB 4.2+ adds support for zstd. + must also be enabled on the server. See `compress network traffic `_ for details. - `zlibCompressionLevel`: (int) The zlib compression level to use when zlib is used as the wire protocol compressor. Supported values @@ -2574,7 +2572,7 @@ def _retryable_error_doc(exc: PyMongoError) -> Optional[Mapping[str, Any]]: return None -def _add_retryable_write_error(exc: PyMongoError, max_wire_version: int, is_mongos: bool) -> None: +def _add_retryable_write_error(exc: PyMongoError) -> None: doc = _retryable_error_doc(exc) if doc: code = doc.get("code", 0) @@ -2586,16 +2584,8 @@ def _add_retryable_write_error(exc: PyMongoError, max_wire_version: int, is_mong "to your connection string." ) raise OperationFailure(errmsg, code, exc.details) # type: ignore[attr-defined] - if max_wire_version >= 9: - # In MongoDB 4.4+, the server reports the error labels. - for label in doc.get("errorLabels", []): - exc._add_error_label(label) - else: - # Do not consult writeConcernError for pre-4.4 mongos. - if isinstance(exc, WriteConcernError) and is_mongos: - pass - elif code in helpers_shared._RETRYABLE_ERROR_CODES: - exc._add_error_label("RetryableWriteError") + for label in doc.get("errorLabels", []): + exc._add_error_label(label) # Connection errors are always retryable except NotPrimaryError and WaitQueueTimeoutError which is # handled above. @@ -2724,14 +2714,6 @@ def __enter__(self) -> Connection: ): session._pin(server, conn) self.contribute_socket(conn) - if ( - self.client._encrypter - and not self.client._encrypter._bypass_auto_encryption - and conn.max_wire_version < 8 - ): - raise ConfigurationError( - "Auto-encryption requires a minimum MongoDB version of 4.2" - ) except BaseException as exc: try: self.handle(type(exc), exc) @@ -3100,17 +3082,13 @@ def _write(self) -> T: :return: Output for func()'s call """ try: - max_wire_version = 0 - is_mongos = False self._server = self._get_server() with self._client._checkout(self._server, self._session) as conn: - max_wire_version = conn.max_wire_version sessions_supported = ( self._session and self._server.description.retryable_writes_supported and conn.supports_sessions ) - is_mongos = conn.is_mongos if not self._always_retryable and not sessions_supported: # A retry is not possible because this server does # not support sessions raise the last error. @@ -3127,7 +3105,7 @@ def _write(self) -> T: if not self._retryable: raise # Add the RetryableWriteError label, if applicable. - _add_retryable_write_error(exc, max_wire_version, is_mongos) + _add_retryable_write_error(exc) raise def _read(self) -> T: diff --git a/pymongo/synchronous/pool.py b/pymongo/synchronous/pool.py index b75415eeeb..64ff4210a5 100644 --- a/pymongo/synchronous/pool.py +++ b/pymongo/synchronous/pool.py @@ -226,7 +226,7 @@ def unpin(self) -> None: def hello_cmd(self) -> dict[str, Any]: # As of PYTHON-5713, always use OP_MSG for the handshake since all - # supported servers (MongoDB 4.2+, wire version >= 8) support it. + # supported servers (MongoDB 4.4+, wire version >= 9) support it. if self.opts.server_api or self.hello_ok or self.opts.load_balanced: return {HelloCompat.CMD: 1} return {HelloCompat.LEGACY_CMD: 1, "helloOk": True} diff --git a/pymongo/synchronous/topology.py b/pymongo/synchronous/topology.py index 4d53af1711..cd451218e1 100644 --- a/pymongo/synchronous/topology.py +++ b/pymongo/synchronous/topology.py @@ -762,8 +762,7 @@ def _handle_error(self, address: _Address, err_ctx: _ErrorContext) -> None: elif isinstance(error, (NotPrimaryError, OperationFailure)): # As per the SDAM spec if: # - the server sees a "not primary" error, and - # - the server is not shutting down, and - # - the server version is >= 4.2, then + # - the server is not shutting down, then # we keep the existing connection pool, but mark the server type # as Unknown and request an immediate check of the server. # Otherwise, we clear the connection pool, mark the server as @@ -776,10 +775,9 @@ def _handle_error(self, address: _Address, err_ctx: _ErrorContext) -> None: err_code = error.details.get("code", default) # type: ignore[union-attr] if err_code in helpers_shared._NOT_PRIMARY_CODES: is_shutting_down = err_code in helpers_shared._SHUTDOWN_CODES - # Mark server Unknown, clear the pool, and request check. if not self._settings.load_balanced: self._process_change(ServerDescription(address, error=error)) - if is_shutting_down or (err_ctx.max_wire_version <= 7): + if is_shutting_down: # Clear the pool. server.reset(service_id) server.request_check() diff --git a/test/__init__.py b/test/__init__.py index 2816edb835..7aff0a4620 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -247,9 +247,6 @@ def _init_client(self): self.cmd_line = self.client.admin.command("getCmdLineOpts") self.server_status = self.client.admin.command("serverStatus") - if self.storage_engine == "mmapv1": - # MMAPv1 does not support retryWrites=True. - self.default_client_options["retryWrites"] = False hello = self.hello self.sessions_enabled = "logicalSessionTimeoutMinutes" in hello @@ -780,13 +777,7 @@ def require_exhaust_cursors(self, func): ) def supports_transactions(self): - if self.version.at_least(4, 1, 8): - return self.is_mongos or self.is_rs - - if self.version.at_least(4, 0): - return self.is_rs - - return False + return self.is_mongos or self.is_rs def require_transactions(self, func): """Run a test only if the deployment might support transactions. @@ -825,16 +816,7 @@ def mongos_seeds(self): @property def supports_failCommand_fail_point(self): """Does the server support the failCommand fail point?""" - if self.is_mongos: - return self.version.at_least(4, 1, 5) and self.test_commands_enabled - else: - return self.version.at_least(4, 0) and self.test_commands_enabled - - @property - def requires_hint_with_min_max_queries(self): - """Does the server require a hint with min/max queries.""" - # Changed in SERVER-39567. - return self.version.at_least(4, 1, 10) + return self.test_commands_enabled @property def max_bson_size(self): diff --git a/test/asynchronous/__init__.py b/test/asynchronous/__init__.py index 5160529ddc..4ecaa589cf 100644 --- a/test/asynchronous/__init__.py +++ b/test/asynchronous/__init__.py @@ -247,9 +247,6 @@ async def _init_client(self): self.cmd_line = await self.client.admin.command("getCmdLineOpts") self.server_status = await self.client.admin.command("serverStatus") - if self.storage_engine == "mmapv1": - # MMAPv1 does not support retryWrites=True. - self.default_client_options["retryWrites"] = False hello = await self.hello self.sessions_enabled = "logicalSessionTimeoutMinutes" in hello @@ -780,13 +777,7 @@ def require_exhaust_cursors(self, func): ) def supports_transactions(self): - if self.version.at_least(4, 1, 8): - return self.is_mongos or self.is_rs - - if self.version.at_least(4, 0): - return self.is_rs - - return False + return self.is_mongos or self.is_rs def require_transactions(self, func): """Run a test only if the deployment might support transactions. @@ -825,16 +816,7 @@ def mongos_seeds(self): @property def supports_failCommand_fail_point(self): """Does the server support the failCommand fail point?""" - if self.is_mongos: - return self.version.at_least(4, 1, 5) and self.test_commands_enabled - else: - return self.version.at_least(4, 0) and self.test_commands_enabled - - @property - def requires_hint_with_min_max_queries(self): - """Does the server require a hint with min/max queries.""" - # Changed in SERVER-39567. - return self.version.at_least(4, 1, 10) + return self.test_commands_enabled @property async def max_bson_size(self): diff --git a/test/asynchronous/test_bulk.py b/test/asynchronous/test_bulk.py index b98983df9a..0052218bd4 100644 --- a/test/asynchronous/test_bulk.py +++ b/test/asynchronous/test_bulk.py @@ -165,7 +165,6 @@ async def _test_update_many(self, update): async def test_update_many(self): await self._test_update_many({"$set": {"foo": "bar"}}) - @async_client_context.require_version_min(4, 2, 0) async def test_update_many_pipeline(self): await self._test_update_many([{"$set": {"foo": "bar"}}]) @@ -206,7 +205,6 @@ async def _test_update_one(self, update): async def test_update_one(self): await self._test_update_one({"$set": {"foo": "bar"}}) - @async_client_context.require_version_min(4, 2, 0) async def test_update_one_pipeline(self): await self._test_update_one([{"$set": {"foo": "bar"}}]) diff --git a/test/asynchronous/test_change_stream.py b/test/asynchronous/test_change_stream.py index 508a42502a..6b1b7b4cb9 100644 --- a/test/asynchronous/test_change_stream.py +++ b/test/asynchronous/test_change_stream.py @@ -267,7 +267,6 @@ async def test_batch_size_is_honored(self): # $changeStream.startAtOperationTime was added in 4.0.0. @no_type_check - @async_client_context.require_version_min(4, 2, 0) async def test_start_at_operation_time(self): optime = await self.get_start_at_operation_time() @@ -436,7 +435,6 @@ async def test_change_operations(self): await self._test_get_invalidate_event(change_stream) @no_type_check - @async_client_context.require_version_min(4, 2, 0) async def test_start_after(self): resume_token = await self.get_resume_token(invalidate=True) @@ -452,7 +450,6 @@ async def test_start_after(self): self.assertEqual(change["fullDocument"], {"_id": 2}) @no_type_check - @async_client_context.require_version_min(4, 2, 0) async def test_start_after_resume_process_with_changes(self): resume_token = await self.get_resume_token(invalidate=True) @@ -473,7 +470,6 @@ async def test_start_after_resume_process_with_changes(self): self.assertEqual(change["fullDocument"], {"_id": 3}) @no_type_check - @async_client_context.require_version_min(4, 2) async def test_start_after_resume_process_without_changes(self): resume_token = await self.get_resume_token(invalidate=True) @@ -563,12 +559,10 @@ async def _test_update_resume_token(self, expected_rt_getter): ) # Prose test no. 1 - @async_client_context.require_version_min(4, 2, 0) async def test_update_resume_token(self): await self._test_update_resume_token(self._get_expected_resume_token) # Prose test no. 2 - @async_client_context.require_version_min(4, 2, 0) async def test_raises_error_on_missing_id_418plus(self): # Server returns an error on 4.1.8+ await self._test_raises_error_on_missing_id(OperationFailure) @@ -636,7 +630,6 @@ def raise_error(): # Prose test no. 11 @no_type_check - @async_client_context.require_version_min(4, 2, 0) async def test_resumetoken_empty_batch(self): client, listener = await self._client_with_listener("getMore") async with await self.change_stream_with_client(client) as change_stream: @@ -648,7 +641,6 @@ async def test_resumetoken_empty_batch(self): # Prose test no. 11 @no_type_check - @async_client_context.require_version_min(4, 2, 0) async def test_resumetoken_exhausted_batch(self): client, listener = await self._client_with_listener("getMore") async with await self.change_stream_with_client(client) as change_stream: @@ -699,13 +691,11 @@ async def test_resumetoken_uniterated_nonempty_batch_resumeafter(self): # Prose test no. 14 @no_type_check @async_client_context.require_no_mongos - @async_client_context.require_version_min(4, 2, 0) async def test_resumetoken_uniterated_nonempty_batch_startafter(self): await self._test_resumetoken_uniterated_nonempty_batch("start_after") # Prose test no. 17 @no_type_check - @async_client_context.require_version_min(4, 2, 0) async def test_startafter_resume_uses_startafter_after_empty_getMore(self): # Resume should use startAfter after no changes have been returned. resume_point = await self.get_resume_token() @@ -725,7 +715,6 @@ async def test_startafter_resume_uses_startafter_after_empty_getMore(self): # Prose test no. 18 @no_type_check - @async_client_context.require_version_min(4, 2, 0) async def test_startafter_resume_uses_resumeafter_after_nonempty_getMore(self): # Resume should use resumeAfter after some changes have been returned. resume_point = await self.get_resume_token() @@ -772,7 +761,6 @@ async def test_split_large_change(self): class TestClusterAsyncChangeStream(TestAsyncChangeStreamBase, APITestsMixin): dbs: list - @async_client_context.require_version_min(4, 2, 0) # type:ignore[untyped-decorator] @async_client_context.require_change_streams # type:ignore[untyped-decorator] async def asyncSetUp(self) -> None: await super().asyncSetUp() @@ -832,7 +820,6 @@ async def test_full_pipeline(self): class TestAsyncDatabaseAsyncChangeStream(TestAsyncChangeStreamBase, APITestsMixin): - @async_client_context.require_version_min(4, 2, 0) # type:ignore[untyped-decorator] @async_client_context.require_change_streams # type:ignore[untyped-decorator] async def asyncSetUp(self) -> None: await super().asyncSetUp() @@ -996,7 +983,6 @@ async def test_raw(self): self.assertEqual(change["ns"]["coll"], self.watched_collection().name) self.assertEqual(change["fullDocument"], raw_doc) - @async_client_context.require_version_min(4, 0) # Needed for start_at_operation_time. async def test_uuid_representations(self): """Test with uuid document _ids and different uuid_representation.""" optime = (await self.db.command("ping"))["operationTime"] diff --git a/test/asynchronous/test_collection.py b/test/asynchronous/test_collection.py index 813c46d778..b3f0391057 100644 --- a/test/asynchronous/test_collection.py +++ b/test/asynchronous/test_collection.py @@ -270,17 +270,7 @@ async def test_create_indexes(self): with self.write_concern_collection() as coll: await coll.create_indexes([IndexModel("hello")]) - @async_client_context.require_version_max(4, 3, -1) - async def test_create_indexes_commitQuorum_requires_44(self): - db = self.db - with self.assertRaisesRegex( - ConfigurationError, - r"Must be connected to MongoDB 4\.4\+ to use the commitQuorum option for createIndexes", - ): - await db.coll.create_indexes([IndexModel("a")], commitQuorum="majority") - @async_client_context.require_no_standalone - @async_client_context.require_version_min(4, 4, -1) async def test_create_indexes_commitQuorum(self): await self.db.coll.create_indexes([IndexModel("a")], commitQuorum="majority") @@ -1872,12 +1862,8 @@ async def test_exhaust(self): # and the socket has pending data (more_to_come=True) we have to close # and discard the socket. cur = client[self.db.name].test.find(cursor_type=CursorType.EXHAUST, batch_size=2) - if async_client_context.version.at_least(4, 2): - # On 4.2+ we use OP_MSG which only sets more_to_come=True after the - # first getMore. - for _ in range(3): - await anext(cur) - else: + # OP_MSG only sets more_to_come=True after the first getMore. + for _ in range(3): await anext(cur) self.assertEqual(0, len(pool.conns)) # if sys.platform.startswith("java") or "PyPy" in sys.version: diff --git a/test/asynchronous/test_connections_survive_primary_stepdown_spec.py b/test/asynchronous/test_connections_survive_primary_stepdown_spec.py index 7ce93ab360..f3b729316e 100644 --- a/test/asynchronous/test_connections_survive_primary_stepdown_spec.py +++ b/test/asynchronous/test_connections_survive_primary_stepdown_spec.py @@ -74,7 +74,6 @@ def verify_pool_cleared(self): def verify_pool_not_cleared(self): self.assertEqual(self.listener.event_count(monitoring.PoolClearedEvent), 0) - @async_client_context.require_version_min(4, 2, -1) async def test_get_more_iteration(self): # Insert 5 documents with WC majority. await self.coll.insert_many([{"data": k} for k in range(5)]) @@ -118,17 +117,14 @@ async def run_scenario(self, error_code, retry, pool_status_checker): # Always retry here to ensure discovery of new primary. await self.coll.insert_one({"test": 1}) - @async_client_context.require_version_min(4, 2, -1) @async_client_context.require_test_commands async def test_not_primary_keep_connection_pool(self): await self.run_scenario(10107, True, self.verify_pool_not_cleared) - @async_client_context.require_version_min(4, 2, 0) @async_client_context.require_test_commands async def test_shutdown_in_progress(self): await self.run_scenario(91, False, self.verify_pool_cleared) - @async_client_context.require_version_min(4, 2, 0) @async_client_context.require_test_commands async def test_interrupted_at_shutdown(self): await self.run_scenario(11600, False, self.verify_pool_cleared) diff --git a/test/asynchronous/test_csot.py b/test/asynchronous/test_csot.py index a3989c9c18..2566c141fb 100644 --- a/test/asynchronous/test_csot.py +++ b/test/asynchronous/test_csot.py @@ -90,9 +90,6 @@ async def test_change_stream_can_resume_after_timeouts(self): await stream.try_next() self.assertTrue(ctx.exception.timeout) self.assertTrue(stream.alive) - # Resume before the insert on 3.6 because 4.0 is required to avoid skipping documents - if async_client_context.version < (4, 0): - await stream.try_next() await coll.insert_one({}) with pymongo.timeout(10): self.assertTrue(await stream.next()) diff --git a/test/asynchronous/test_cursor.py b/test/asynchronous/test_cursor.py index 1fe023720a..f8fbac8032 100644 --- a/test/asynchronous/test_cursor.py +++ b/test/asynchronous/test_cursor.py @@ -855,16 +855,13 @@ async def test_where(self): self.assertEqual(3, len(await db.test.find().where(Code("this.x < 3")).to_list())) code_with_scope = Code("this.x < i", {"i": 3}) - if async_client_context.version.at_least(4, 3, 3): - # MongoDB 4.4 removed support for Code with scope. - with self.assertRaises(OperationFailure): - await db.test.find().where(code_with_scope).to_list() - - code_with_empty_scope = Code("this.x < 3", {}) - with self.assertRaises(OperationFailure): - await db.test.find().where(code_with_empty_scope).to_list() - else: - self.assertEqual(3, len(await db.test.find().where(code_with_scope).to_list())) + # MongoDB 4.4 removed support for Code with scope. + with self.assertRaises(OperationFailure): + await db.test.find().where(code_with_scope).to_list() + + code_with_empty_scope = Code("this.x < 3", {}) + with self.assertRaises(OperationFailure): + await db.test.find().where(code_with_empty_scope).to_list() self.assertEqual(10, len(await db.test.find().to_list())) self.assertEqual([0, 1, 2], [a["x"] async for a in db.test.find().where("this.x < 3")]) diff --git a/test/asynchronous/test_custom_types.py b/test/asynchronous/test_custom_types.py index c0564dd876..613a5083db 100644 --- a/test/asynchronous/test_custom_types.py +++ b/test/asynchronous/test_custom_types.py @@ -932,7 +932,6 @@ async def create_targets(self, *args, **kwargs): class TestDatabaseChangeStreamsWCustomTypes( AsyncIntegrationTest, ChangeStreamsWCustomTypesTestMixin ): - @async_client_context.require_version_min(4, 2, 0) @async_client_context.require_change_streams async def asyncSetUp(self): await super().asyncSetUp() @@ -952,7 +951,6 @@ async def create_targets(self, *args, **kwargs): class TestClusterChangeStreamsWCustomTypes( AsyncIntegrationTest, ChangeStreamsWCustomTypesTestMixin ): - @async_client_context.require_version_min(4, 2, 0) @async_client_context.require_change_streams async def asyncSetUp(self): await super().asyncSetUp() diff --git a/test/asynchronous/test_database.py b/test/asynchronous/test_database.py index e8b37f6405..4b9f41c244 100644 --- a/test/asynchronous/test_database.py +++ b/test/asynchronous/test_database.py @@ -382,7 +382,6 @@ async def test_validate_collection(self): self.assertTrue(await db.validate_collection(db.test, scandata=True, full=True)) self.assertTrue(await db.validate_collection(db.test, True, True)) - @async_client_context.require_version_min(4, 3, 3) @async_client_context.require_no_standalone async def test_validate_collection_background(self): db = self.client.pymongo_test.with_options(write_concern=WriteConcern(w="majority")) @@ -710,15 +709,10 @@ async def test_database_aggregation(self): @async_client_context.require_no_mongos async def test_database_aggregation_fake_cursor(self): coll_name = "test_output" - write_stage: dict - if async_client_context.version < (4, 3): - db_name = "admin" - write_stage = {"$out": coll_name} - else: - # SERVER-43287 disallows writing with $out to the admin db, use - # $merge instead. - db_name = "pymongo_test" - write_stage = {"$merge": {"into": {"db": db_name, "coll": coll_name}}} + # SERVER-43287 disallows writing with $out to the admin db, use + # $merge instead. + db_name = "pymongo_test" + write_stage = {"$merge": {"into": {"db": db_name, "coll": coll_name}}} output_coll = self.client[db_name][coll_name] await output_coll.drop() self.addAsyncCleanup(output_coll.drop) diff --git a/test/asynchronous/test_discovery_and_monitoring.py b/test/asynchronous/test_discovery_and_monitoring.py index 84382cf86f..90a977577f 100644 --- a/test/asynchronous/test_discovery_and_monitoring.py +++ b/test/asynchronous/test_discovery_and_monitoring.py @@ -269,6 +269,22 @@ def create_tests(): test_name = f"test_{dirname}_{os.path.splitext(filename)[0]}" new_test.__name__ = test_name + + # Skip scenarios where all mock server responses report a wire + # version below the minimum supported (server no longer reachable). + max_version = max( + ( + r[1].get("maxWireVersion", 0) + for phase in scenario_def.get("phases", []) + for r in phase.get("responses", []) + ), + default=common.MIN_SUPPORTED_WIRE_VERSION, + ) + if max_version < common.MIN_SUPPORTED_WIRE_VERSION: + new_test = unittest.skip( + f"Server wire version {max_version} is below minimum {common.MIN_SUPPORTED_WIRE_VERSION}" + )(new_test) + setattr(TestAllScenarios, new_test.__name__, new_test) diff --git a/test/asynchronous/test_encryption.py b/test/asynchronous/test_encryption.py index daeb18607a..5b0a7c0bba 100644 --- a/test/asynchronous/test_encryption.py +++ b/test/asynchronous/test_encryption.py @@ -233,7 +233,6 @@ class AsyncEncryptionIntegrationTest(AsyncIntegrationTest): """Base class for encryption integration tests.""" @unittest.skipUnless(_HAVE_PYMONGOCRYPT, "pymongocrypt is not installed") - @async_client_context.require_version_min(4, 2, -1) # type:ignore[untyped-decorator] async def asyncSetUp(self) -> None: await super().asyncSetUp() diff --git a/test/asynchronous/test_examples.py b/test/asynchronous/test_examples.py index 58ce1621c1..6a6d6b3d9e 100644 --- a/test/asynchronous/test_examples.py +++ b/test/asynchronous/test_examples.py @@ -862,7 +862,6 @@ async def test_aggregate_examples(self): ) # End Aggregation Example 4 - @async_client_context.require_version_min(4, 4) async def test_aggregate_projection_example(self): db = self.db diff --git a/test/asynchronous/test_monitoring.py b/test/asynchronous/test_monitoring.py index 7d6075ad48..c29ab71cc2 100644 --- a/test/asynchronous/test_monitoring.py +++ b/test/asynchronous/test_monitoring.py @@ -279,19 +279,6 @@ async def test_find_options(self): "allowPartialResults": True, } - if async_client_context.version < (4, 1, 0, -1): - query["max_scan"] = 10 - cmd["maxScan"] = 10 - - await self._test_find_options(query, cmd) - - @async_client_context.require_version_max(3, 7, 2) - async def test_find_snapshot(self): - # Test "snapshot" parameter separately, can't combine with "sort". - query = {"filter": {}, "snapshot": True} - - cmd = {"find": "test", "filter": {}, "snapshot": True} - await self._test_find_options(query, cmd) async def test_command_and_get_more(self): diff --git a/test/asynchronous/test_on_demand_csfle.py b/test/asynchronous/test_on_demand_csfle.py index cd1592318e..b69674b729 100644 --- a/test/asynchronous/test_on_demand_csfle.py +++ b/test/asynchronous/test_on_demand_csfle.py @@ -39,7 +39,6 @@ class TestonDemandGCPCredentials(AsyncIntegrationTest): @unittest.skipUnless(_HAVE_PYMONGOCRYPT, "pymongocrypt is not installed") - @async_client_context.require_version_min(4, 2, -1) async def asyncSetUp(self): await super().asyncSetUp() self.master_key = { @@ -77,7 +76,6 @@ async def test_02_success(self): class TestonDemandAzureCredentials(AsyncIntegrationTest): @unittest.skipUnless(_HAVE_PYMONGOCRYPT, "pymongocrypt is not installed") - @async_client_context.require_version_min(4, 2, -1) async def asyncSetUp(self): await super().asyncSetUp() self.master_key = { diff --git a/test/asynchronous/test_read_concern.py b/test/asynchronous/test_read_concern.py index 487ae78cf6..b694d8c0bf 100644 --- a/test/asynchronous/test_read_concern.py +++ b/test/asynchronous/test_read_concern.py @@ -111,11 +111,7 @@ async def test_aggregate_out(self): await coll.aggregate([{"$match": {"field": "value"}}, {"$out": "output_collection"}]) ).to_list() - # Aggregate with $out supports readConcern MongoDB 4.2 onwards. - if async_client_context.version >= (4, 1): - self.assertIn("readConcern", self.listener.started_events[0].command) - else: - self.assertNotIn("readConcern", self.listener.started_events[0].command) + self.assertIn("readConcern", self.listener.started_events[0].command) if __name__ == "__main__": diff --git a/test/asynchronous/test_retryable_reads.py b/test/asynchronous/test_retryable_reads.py index 345748a276..ecf621fc7e 100644 --- a/test/asynchronous/test_retryable_reads.py +++ b/test/asynchronous/test_retryable_reads.py @@ -278,7 +278,6 @@ async def test_retryable_reads_are_retried_on_the_same_implicit_session(self): @async_client_context.require_replica_set @async_client_context.require_secondaries_count(1) @async_client_context.require_failCommand_fail_point - @async_client_context.require_version_min(4, 4, 0) async def test_03_01_retryable_reads_caused_by_overload_errors_are_retried_on_a_different_replicaset_server_when_one_is_available_and_overload_retargeting_is_enabled( self, ): @@ -323,7 +322,6 @@ async def test_03_01_retryable_reads_caused_by_overload_errors_are_retried_on_a_ @async_client_context.require_replica_set @async_client_context.require_secondaries_count(1) @async_client_context.require_failCommand_fail_point - @async_client_context.require_version_min(4, 4, 0) async def test_03_02_retryable_reads_caused_by_non_overload_errors_are_retried_on_the_same_replicaset_server( self, ): @@ -365,7 +363,6 @@ async def test_03_02_retryable_reads_caused_by_non_overload_errors_are_retried_o @async_client_context.require_replica_set @async_client_context.require_secondaries_count(1) @async_client_context.require_failCommand_fail_point - @async_client_context.require_version_min(4, 4, 0) async def test_03_03_retryable_reads_caused_by_overload_errors_are_retried_on_the_same_replicaset_server_when_one_is_available_and_overload_retargeting_is_disabled( self, ): @@ -407,7 +404,6 @@ async def test_03_03_retryable_reads_caused_by_overload_errors_are_retried_on_th assert listener.failed_events[0].connection_id == listener.succeeded_events[0].connection_id @async_client_context.require_failCommand_fail_point - @async_client_context.require_version_min(4, 4, 0) # type:ignore[untyped-decorator] async def test_overload_then_nonoverload_retries_increased_reads(self) -> None: # Create a client. listener = OvertCommandListener() @@ -459,7 +455,6 @@ def failed(event: CommandFailedEvent) -> None: self.assertEqual(len(started_finds), MAX_ADAPTIVE_RETRIES + 1) @async_client_context.require_failCommand_fail_point - @async_client_context.require_version_min(4, 4, 0) # type:ignore[untyped-decorator] async def test_backoff_is_not_applied_for_non_overload_errors(self): if _IS_SYNC: mock_target = "pymongo.synchronous.helpers._RetryPolicy.backoff" diff --git a/test/asynchronous/test_retryable_writes.py b/test/asynchronous/test_retryable_writes.py index 9055e6dcd3..90be59016a 100644 --- a/test/asynchronous/test_retryable_writes.py +++ b/test/asynchronous/test_retryable_writes.py @@ -413,7 +413,6 @@ async def asyncSetUp(self) -> None: }, } - @async_client_context.require_version_min(4, 0) @client_knobs(heartbeat_frequency=0.05, min_heartbeat_interval=0.05) async def test_RetryableWriteError_error_label(self): listener = OvertCommandListener() @@ -431,7 +430,6 @@ async def test_RetryableWriteError_error_label(self): # In MongoDB 4.4+ we rely on the server returning the error label. self.assertIn("RetryableWriteError", listener.succeeded_events[-1].reply["errorLabels"]) - @async_client_context.require_version_min(4, 4) async def test_RetryableWriteError_error_label_RawBSONDocument(self): # using RawBSONDocument should not cause errorLabel parsing to fail async with self.fail_point(self.fail_insert): diff --git a/test/asynchronous/test_sdam_monitoring_spec.py b/test/asynchronous/test_sdam_monitoring_spec.py index dc4fda9b3e..5ffeb81eb9 100644 --- a/test/asynchronous/test_sdam_monitoring_spec.py +++ b/test/asynchronous/test_sdam_monitoring_spec.py @@ -356,15 +356,6 @@ def marked_unknown_and_rediscovered(): async def test_network_error_publishes_events(self): await self._test_app_error({"closeConnection": True}, ConnectionFailure) - # In 4.4+, not primary errors from failCommand don't cause SDAM state - # changes because topologyVersion is not incremented. - @async_client_context.require_version_max(4, 3) - async def test_not_primary_error_publishes_events(self): - await self._test_app_error( - {"errorCode": 10107, "closeConnection": False, "errorLabels": ["RetryableWriteError"]}, - NotPrimaryError, - ) - async def test_shutdown_error_publishes_events(self): await self._test_app_error( {"errorCode": 91, "closeConnection": False, "errorLabels": ["RetryableWriteError"]}, diff --git a/test/asynchronous/test_transactions.py b/test/asynchronous/test_transactions.py index 2542da2faa..186dc4fee2 100644 --- a/test/asynchronous/test_transactions.py +++ b/test/asynchronous/test_transactions.py @@ -139,14 +139,6 @@ async def test_transaction_write_concern_override(self): (coll.drop_indexes, [], {}), (coll.aggregate, [[{"$out": "aggout"}]], {}), ] - # Creating a collection in a transaction requires MongoDB 4.4+. - if async_client_context.version < (4, 3, 4): - unsupported_txn_writes.extend( - [ - (db.create_collection, ["collection"], {}), - ] - ) - for op in unsupported_txn_writes: op, args, kwargs = op async with client.start_session() as s: @@ -214,7 +206,6 @@ async def test_unpin_for_non_transaction_operation(self): self.assertGreater(len(addresses), 1) @async_client_context.require_transactions - @async_client_context.require_version_min(4, 3, 4) async def test_create_collection(self): client = async_client_context.client db = client.pymongo_test @@ -315,8 +306,6 @@ async def gridfs_open_upload_stream(*args, **kwargs): ): await op(*args, session=s) # type: ignore - # Require 4.2+ for large (16MB+) transactions. - @async_client_context.require_version_min(4, 2) @async_client_context.require_transactions @unittest.skipIf(sys.platform == "win32", "Our Windows machines are too slow to pass this test") async def test_transaction_starts_with_batched_write(self): diff --git a/test/mockupdb/test_cursor_namespace.py b/test/mockupdb/test_cursor_namespace.py index f77f4a5c2c..adc73ee4e6 100644 --- a/test/mockupdb/test_cursor_namespace.py +++ b/test/mockupdb/test_cursor_namespace.py @@ -42,7 +42,7 @@ class TestCursorNamespace(PyMongoTestCase): @classmethod def setUpClass(cls): - cls.server = MockupDB(auto_ismaster={"maxWireVersion": 8}) + cls.server = MockupDB(auto_ismaster={"maxWireVersion": MIN_SUPPORTED_WIRE_VERSION}) cls.server.run() cls.client = cls.unmanaged_simple_client(cls.server.uri) diff --git a/test/mockupdb/test_op_msg.py b/test/mockupdb/test_op_msg.py index a509d13182..2b97464593 100644 --- a/test/mockupdb/test_op_msg.py +++ b/test/mockupdb/test_op_msg.py @@ -28,6 +28,7 @@ _HAVE_MOCKUPDB = False from pymongo import MongoClient, WriteConcern +from pymongo.common import MIN_SUPPORTED_WIRE_VERSION from pymongo.cursor_shared import CursorType from pymongo.operations import DeleteOne, InsertOne, UpdateOne @@ -281,7 +282,7 @@ class TestOpMsg(PyMongoTestCase): @classmethod def setUpClass(cls): - cls.server = MockupDB(auto_ismaster=True, max_wire_version=8) + cls.server = MockupDB(auto_ismaster=True, max_wire_version=MIN_SUPPORTED_WIRE_VERSION) cls.server.run() cls.client = cls.unmanaged_simple_client(cls.server.uri) diff --git a/test/mockupdb/test_standalone_shard.py b/test/mockupdb/test_standalone_shard.py index c290d63bce..c5f1517484 100644 --- a/test/mockupdb/test_standalone_shard.py +++ b/test/mockupdb/test_standalone_shard.py @@ -29,6 +29,7 @@ from pymongo import MongoClient +from pymongo.common import MIN_SUPPORTED_WIRE_VERSION from pymongo.errors import OperationFailure pytestmark = pytest.mark.mockupdb @@ -37,7 +38,7 @@ class TestStandaloneShard(unittest.TestCase): # See PYTHON-2048 and SERVER-44591. def test_bulk_txn_error_message(self): - server = MockupDB(auto_ismaster={"maxWireVersion": 8}) + server = MockupDB(auto_ismaster={"maxWireVersion": MIN_SUPPORTED_WIRE_VERSION}) server.run() self.addCleanup(server.stop) client = MongoClient(server.uri) diff --git a/test/test_bulk.py b/test/test_bulk.py index baefb1ad30..113c905a9b 100644 --- a/test/test_bulk.py +++ b/test/test_bulk.py @@ -165,7 +165,6 @@ def _test_update_many(self, update): def test_update_many(self): self._test_update_many({"$set": {"foo": "bar"}}) - @client_context.require_version_min(4, 2, 0) def test_update_many_pipeline(self): self._test_update_many([{"$set": {"foo": "bar"}}]) @@ -206,7 +205,6 @@ def _test_update_one(self, update): def test_update_one(self): self._test_update_one({"$set": {"foo": "bar"}}) - @client_context.require_version_min(4, 2, 0) def test_update_one_pipeline(self): self._test_update_one([{"$set": {"foo": "bar"}}]) diff --git a/test/test_change_stream.py b/test/test_change_stream.py index 01f73edd9a..5fb0f6046d 100644 --- a/test/test_change_stream.py +++ b/test/test_change_stream.py @@ -263,7 +263,6 @@ def test_batch_size_is_honored(self): # $changeStream.startAtOperationTime was added in 4.0.0. @no_type_check - @client_context.require_version_min(4, 2, 0) def test_start_at_operation_time(self): optime = self.get_start_at_operation_time() @@ -432,7 +431,6 @@ def test_change_operations(self): self._test_get_invalidate_event(change_stream) @no_type_check - @client_context.require_version_min(4, 2, 0) def test_start_after(self): resume_token = self.get_resume_token(invalidate=True) @@ -448,7 +446,6 @@ def test_start_after(self): self.assertEqual(change["fullDocument"], {"_id": 2}) @no_type_check - @client_context.require_version_min(4, 2, 0) def test_start_after_resume_process_with_changes(self): resume_token = self.get_resume_token(invalidate=True) @@ -467,7 +464,6 @@ def test_start_after_resume_process_with_changes(self): self.assertEqual(change["fullDocument"], {"_id": 3}) @no_type_check - @client_context.require_version_min(4, 2) def test_start_after_resume_process_without_changes(self): resume_token = self.get_resume_token(invalidate=True) @@ -553,12 +549,10 @@ def _test_update_resume_token(self, expected_rt_getter): ) # Prose test no. 1 - @client_context.require_version_min(4, 2, 0) def test_update_resume_token(self): self._test_update_resume_token(self._get_expected_resume_token) # Prose test no. 2 - @client_context.require_version_min(4, 2, 0) def test_raises_error_on_missing_id_418plus(self): # Server returns an error on 4.1.8+ self._test_raises_error_on_missing_id(OperationFailure) @@ -626,7 +620,6 @@ def raise_error(): # Prose test no. 11 @no_type_check - @client_context.require_version_min(4, 2, 0) def test_resumetoken_empty_batch(self): client, listener = self._client_with_listener("getMore") with self.change_stream_with_client(client) as change_stream: @@ -638,7 +631,6 @@ def test_resumetoken_empty_batch(self): # Prose test no. 11 @no_type_check - @client_context.require_version_min(4, 2, 0) def test_resumetoken_exhausted_batch(self): client, listener = self._client_with_listener("getMore") with self.change_stream_with_client(client) as change_stream: @@ -689,13 +681,11 @@ def test_resumetoken_uniterated_nonempty_batch_resumeafter(self): # Prose test no. 14 @no_type_check @client_context.require_no_mongos - @client_context.require_version_min(4, 2, 0) def test_resumetoken_uniterated_nonempty_batch_startafter(self): self._test_resumetoken_uniterated_nonempty_batch("start_after") # Prose test no. 17 @no_type_check - @client_context.require_version_min(4, 2, 0) def test_startafter_resume_uses_startafter_after_empty_getMore(self): # Resume should use startAfter after no changes have been returned. resume_point = self.get_resume_token() @@ -713,7 +703,6 @@ def test_startafter_resume_uses_startafter_after_empty_getMore(self): # Prose test no. 18 @no_type_check - @client_context.require_version_min(4, 2, 0) def test_startafter_resume_uses_resumeafter_after_nonempty_getMore(self): # Resume should use resumeAfter after some changes have been returned. resume_point = self.get_resume_token() @@ -758,7 +747,6 @@ def test_split_large_change(self): class TestClusterChangeStream(TestChangeStreamBase, APITestsMixin): dbs: list - @client_context.require_version_min(4, 2, 0) # type:ignore[untyped-decorator] @client_context.require_change_streams # type:ignore[untyped-decorator] def setUp(self) -> None: super().setUp() @@ -818,7 +806,6 @@ def test_full_pipeline(self): class TestDatabaseChangeStream(TestChangeStreamBase, APITestsMixin): - @client_context.require_version_min(4, 2, 0) # type:ignore[untyped-decorator] @client_context.require_change_streams # type:ignore[untyped-decorator] def setUp(self) -> None: super().setUp() @@ -978,7 +965,6 @@ def test_raw(self): self.assertEqual(change["ns"]["coll"], self.watched_collection().name) self.assertEqual(change["fullDocument"], raw_doc) - @client_context.require_version_min(4, 0) # Needed for start_at_operation_time. def test_uuid_representations(self): """Test with uuid document _ids and different uuid_representation.""" optime = (self.db.command("ping"))["operationTime"] diff --git a/test/test_collection.py b/test/test_collection.py index d2dd02cf41..ae389d9166 100644 --- a/test/test_collection.py +++ b/test/test_collection.py @@ -270,17 +270,7 @@ def test_create_indexes(self): with self.write_concern_collection() as coll: coll.create_indexes([IndexModel("hello")]) - @client_context.require_version_max(4, 3, -1) - def test_create_indexes_commitQuorum_requires_44(self): - db = self.db - with self.assertRaisesRegex( - ConfigurationError, - r"Must be connected to MongoDB 4\.4\+ to use the commitQuorum option for createIndexes", - ): - db.coll.create_indexes([IndexModel("a")], commitQuorum="majority") - @client_context.require_no_standalone - @client_context.require_version_min(4, 4, -1) def test_create_indexes_commitQuorum(self): self.db.coll.create_indexes([IndexModel("a")], commitQuorum="majority") @@ -1854,12 +1844,8 @@ def test_exhaust(self): # and the socket has pending data (more_to_come=True) we have to close # and discard the socket. cur = client[self.db.name].test.find(cursor_type=CursorType.EXHAUST, batch_size=2) - if client_context.version.at_least(4, 2): - # On 4.2+ we use OP_MSG which only sets more_to_come=True after the - # first getMore. - for _ in range(3): - next(cur) - else: + # OP_MSG only sets more_to_come=True after the first getMore. + for _ in range(3): next(cur) self.assertEqual(0, len(pool.conns)) # if sys.platform.startswith("java") or "PyPy" in sys.version: diff --git a/test/test_connections_survive_primary_stepdown_spec.py b/test/test_connections_survive_primary_stepdown_spec.py index 51d37b7c57..dfcec79322 100644 --- a/test/test_connections_survive_primary_stepdown_spec.py +++ b/test/test_connections_survive_primary_stepdown_spec.py @@ -74,7 +74,6 @@ def verify_pool_cleared(self): def verify_pool_not_cleared(self): self.assertEqual(self.listener.event_count(monitoring.PoolClearedEvent), 0) - @client_context.require_version_min(4, 2, -1) def test_get_more_iteration(self): # Insert 5 documents with WC majority. self.coll.insert_many([{"data": k} for k in range(5)]) @@ -118,17 +117,14 @@ def run_scenario(self, error_code, retry, pool_status_checker): # Always retry here to ensure discovery of new primary. self.coll.insert_one({"test": 1}) - @client_context.require_version_min(4, 2, -1) @client_context.require_test_commands def test_not_primary_keep_connection_pool(self): self.run_scenario(10107, True, self.verify_pool_not_cleared) - @client_context.require_version_min(4, 2, 0) @client_context.require_test_commands def test_shutdown_in_progress(self): self.run_scenario(91, False, self.verify_pool_cleared) - @client_context.require_version_min(4, 2, 0) @client_context.require_test_commands def test_interrupted_at_shutdown(self): self.run_scenario(11600, False, self.verify_pool_cleared) diff --git a/test/test_csot.py b/test/test_csot.py index da6c1ca384..2b1997c945 100644 --- a/test/test_csot.py +++ b/test/test_csot.py @@ -90,9 +90,6 @@ def test_change_stream_can_resume_after_timeouts(self): stream.try_next() self.assertTrue(ctx.exception.timeout) self.assertTrue(stream.alive) - # Resume before the insert on 3.6 because 4.0 is required to avoid skipping documents - if client_context.version < (4, 0): - stream.try_next() coll.insert_one({}) with pymongo.timeout(10): self.assertTrue(stream.next()) diff --git a/test/test_cursor.py b/test/test_cursor.py index 58aae5f0f9..806dba45c9 100644 --- a/test/test_cursor.py +++ b/test/test_cursor.py @@ -846,16 +846,13 @@ def test_where(self): self.assertEqual(3, len(db.test.find().where(Code("this.x < 3")).to_list())) code_with_scope = Code("this.x < i", {"i": 3}) - if client_context.version.at_least(4, 3, 3): - # MongoDB 4.4 removed support for Code with scope. - with self.assertRaises(OperationFailure): - db.test.find().where(code_with_scope).to_list() - - code_with_empty_scope = Code("this.x < 3", {}) - with self.assertRaises(OperationFailure): - db.test.find().where(code_with_empty_scope).to_list() - else: - self.assertEqual(3, len(db.test.find().where(code_with_scope).to_list())) + # MongoDB 4.4 removed support for Code with scope. + with self.assertRaises(OperationFailure): + db.test.find().where(code_with_scope).to_list() + + code_with_empty_scope = Code("this.x < 3", {}) + with self.assertRaises(OperationFailure): + db.test.find().where(code_with_empty_scope).to_list() self.assertEqual(10, len(db.test.find().to_list())) self.assertEqual([0, 1, 2], [a["x"] for a in db.test.find().where("this.x < 3")]) diff --git a/test/test_custom_types.py b/test/test_custom_types.py index b55eb64d9d..b15449c2f5 100644 --- a/test/test_custom_types.py +++ b/test/test_custom_types.py @@ -928,7 +928,6 @@ def create_targets(self, *args, **kwargs): class TestDatabaseChangeStreamsWCustomTypes(IntegrationTest, ChangeStreamsWCustomTypesTestMixin): - @client_context.require_version_min(4, 2, 0) @client_context.require_change_streams def setUp(self): super().setUp() @@ -946,7 +945,6 @@ def create_targets(self, *args, **kwargs): class TestClusterChangeStreamsWCustomTypes(IntegrationTest, ChangeStreamsWCustomTypesTestMixin): - @client_context.require_version_min(4, 2, 0) @client_context.require_change_streams def setUp(self): super().setUp() diff --git a/test/test_database.py b/test/test_database.py index 61d2494eb9..f1932c86fa 100644 --- a/test/test_database.py +++ b/test/test_database.py @@ -377,7 +377,6 @@ def test_validate_collection(self): self.assertTrue(db.validate_collection(db.test, scandata=True, full=True)) self.assertTrue(db.validate_collection(db.test, True, True)) - @client_context.require_version_min(4, 3, 3) @client_context.require_no_standalone def test_validate_collection_background(self): db = self.client.pymongo_test.with_options(write_concern=WriteConcern(w="majority")) @@ -701,15 +700,10 @@ def test_database_aggregation(self): @client_context.require_no_mongos def test_database_aggregation_fake_cursor(self): coll_name = "test_output" - write_stage: dict - if client_context.version < (4, 3): - db_name = "admin" - write_stage = {"$out": coll_name} - else: - # SERVER-43287 disallows writing with $out to the admin db, use - # $merge instead. - db_name = "pymongo_test" - write_stage = {"$merge": {"into": {"db": db_name, "coll": coll_name}}} + # SERVER-43287 disallows writing with $out to the admin db, use + # $merge instead. + db_name = "pymongo_test" + write_stage = {"$merge": {"into": {"db": db_name, "coll": coll_name}}} output_coll = self.client[db_name][coll_name] output_coll.drop() self.addCleanup(output_coll.drop) diff --git a/test/test_discovery_and_monitoring.py b/test/test_discovery_and_monitoring.py index 7b36cc318a..3925480f73 100644 --- a/test/test_discovery_and_monitoring.py +++ b/test/test_discovery_and_monitoring.py @@ -269,6 +269,22 @@ def create_tests(): test_name = f"test_{dirname}_{os.path.splitext(filename)[0]}" new_test.__name__ = test_name + + # Skip scenarios where all mock server responses report a wire + # version below the minimum supported (server no longer reachable). + max_version = max( + ( + r[1].get("maxWireVersion", 0) + for phase in scenario_def.get("phases", []) + for r in phase.get("responses", []) + ), + default=common.MIN_SUPPORTED_WIRE_VERSION, + ) + if max_version < common.MIN_SUPPORTED_WIRE_VERSION: + new_test = unittest.skip( + f"Server wire version {max_version} is below minimum {common.MIN_SUPPORTED_WIRE_VERSION}" + )(new_test) + setattr(TestAllScenarios, new_test.__name__, new_test) diff --git a/test/test_encryption.py b/test/test_encryption.py index 744db01b1b..23a2405aa7 100644 --- a/test/test_encryption.py +++ b/test/test_encryption.py @@ -233,7 +233,6 @@ class EncryptionIntegrationTest(IntegrationTest): """Base class for encryption integration tests.""" @unittest.skipUnless(_HAVE_PYMONGOCRYPT, "pymongocrypt is not installed") - @client_context.require_version_min(4, 2, -1) # type:ignore[untyped-decorator] def setUp(self) -> None: super().setUp() diff --git a/test/test_examples.py b/test/test_examples.py index ccc709e3aa..b97e1f7bfa 100644 --- a/test/test_examples.py +++ b/test/test_examples.py @@ -862,7 +862,6 @@ def test_aggregate_examples(self): ) # End Aggregation Example 4 - @client_context.require_version_min(4, 4) def test_aggregate_projection_example(self): db = self.db diff --git a/test/test_message.py b/test/test_message.py index 9c11ffef5b..9f477fa36f 100644 --- a/test/test_message.py +++ b/test/test_message.py @@ -444,45 +444,28 @@ def test_get_more_basic(self): batch_size=None, max_await_time_ms=None, comment=None, - conn=self._make_conn(), ) self.assertEqual(cmd["getMore"], 12345) self.assertEqual(cmd["collection"], "col") def test_get_more_with_batch_size(self): - cmd = _gen_get_more_command( - 1, "col", batch_size=100, max_await_time_ms=None, comment=None, conn=self._make_conn() - ) + cmd = _gen_get_more_command(1, "col", batch_size=100, max_await_time_ms=None, comment=None) self.assertEqual(cmd["batchSize"], 100) def test_get_more_with_max_await_time_ms(self): - cmd = _gen_get_more_command( - 1, "col", batch_size=None, max_await_time_ms=500, comment=None, conn=self._make_conn() - ) + cmd = _gen_get_more_command(1, "col", batch_size=None, max_await_time_ms=500, comment=None) self.assertEqual(cmd["maxTimeMS"], 500) - def test_get_more_comment_added_on_high_wire_version(self): + def test_get_more_with_comment(self): cmd = _gen_get_more_command( 1, "col", batch_size=None, max_await_time_ms=None, comment="my comment", - conn=self._make_conn(9), ) self.assertEqual(cmd["comment"], "my comment") - def test_get_more_comment_not_added_on_low_wire_version(self): - cmd = _gen_get_more_command( - 1, - "col", - batch_size=None, - max_await_time_ms=None, - comment="my comment", - conn=self._make_conn(8), - ) - self.assertNotIn("comment", cmd) - if __name__ == "__main__": unittest.main() diff --git a/test/test_monitoring.py b/test/test_monitoring.py index ec24acb4a0..fde78a7c1e 100644 --- a/test/test_monitoring.py +++ b/test/test_monitoring.py @@ -277,19 +277,6 @@ def test_find_options(self): "allowPartialResults": True, } - if client_context.version < (4, 1, 0, -1): - query["max_scan"] = 10 - cmd["maxScan"] = 10 - - self._test_find_options(query, cmd) - - @client_context.require_version_max(3, 7, 2) - def test_find_snapshot(self): - # Test "snapshot" parameter separately, can't combine with "sort". - query = {"filter": {}, "snapshot": True} - - cmd = {"find": "test", "filter": {}, "snapshot": True} - self._test_find_options(query, cmd) def test_command_and_get_more(self): diff --git a/test/test_on_demand_csfle.py b/test/test_on_demand_csfle.py index 24a0f917e2..607752524d 100644 --- a/test/test_on_demand_csfle.py +++ b/test/test_on_demand_csfle.py @@ -39,7 +39,6 @@ class TestonDemandGCPCredentials(IntegrationTest): @unittest.skipUnless(_HAVE_PYMONGOCRYPT, "pymongocrypt is not installed") - @client_context.require_version_min(4, 2, -1) def setUp(self): super().setUp() self.master_key = { @@ -77,7 +76,6 @@ def test_02_success(self): class TestonDemandAzureCredentials(IntegrationTest): @unittest.skipUnless(_HAVE_PYMONGOCRYPT, "pymongocrypt is not installed") - @client_context.require_version_min(4, 2, -1) def setUp(self): super().setUp() self.master_key = { diff --git a/test/test_read_concern.py b/test/test_read_concern.py index 93398d14c9..f9b2faf67f 100644 --- a/test/test_read_concern.py +++ b/test/test_read_concern.py @@ -109,11 +109,7 @@ def test_aggregate_out(self): coll = self.db.get_collection("coll", read_concern=ReadConcern("local")) (coll.aggregate([{"$match": {"field": "value"}}, {"$out": "output_collection"}])).to_list() - # Aggregate with $out supports readConcern MongoDB 4.2 onwards. - if client_context.version >= (4, 1): - self.assertIn("readConcern", self.listener.started_events[0].command) - else: - self.assertNotIn("readConcern", self.listener.started_events[0].command) + self.assertIn("readConcern", self.listener.started_events[0].command) if __name__ == "__main__": diff --git a/test/test_retryable_reads.py b/test/test_retryable_reads.py index 9a24119020..bf0650393b 100644 --- a/test/test_retryable_reads.py +++ b/test/test_retryable_reads.py @@ -278,7 +278,6 @@ def test_retryable_reads_are_retried_on_the_same_implicit_session(self): @client_context.require_replica_set @client_context.require_secondaries_count(1) @client_context.require_failCommand_fail_point - @client_context.require_version_min(4, 4, 0) def test_03_01_retryable_reads_caused_by_overload_errors_are_retried_on_a_different_replicaset_server_when_one_is_available_and_overload_retargeting_is_enabled( self, ): @@ -323,7 +322,6 @@ def test_03_01_retryable_reads_caused_by_overload_errors_are_retried_on_a_differ @client_context.require_replica_set @client_context.require_secondaries_count(1) @client_context.require_failCommand_fail_point - @client_context.require_version_min(4, 4, 0) def test_03_02_retryable_reads_caused_by_non_overload_errors_are_retried_on_the_same_replicaset_server( self, ): @@ -365,7 +363,6 @@ def test_03_02_retryable_reads_caused_by_non_overload_errors_are_retried_on_the_ @client_context.require_replica_set @client_context.require_secondaries_count(1) @client_context.require_failCommand_fail_point - @client_context.require_version_min(4, 4, 0) def test_03_03_retryable_reads_caused_by_overload_errors_are_retried_on_the_same_replicaset_server_when_one_is_available_and_overload_retargeting_is_disabled( self, ): @@ -407,7 +404,6 @@ def test_03_03_retryable_reads_caused_by_overload_errors_are_retried_on_the_same assert listener.failed_events[0].connection_id == listener.succeeded_events[0].connection_id @client_context.require_failCommand_fail_point - @client_context.require_version_min(4, 4, 0) # type:ignore[untyped-decorator] def test_overload_then_nonoverload_retries_increased_reads(self) -> None: # Create a client. listener = OvertCommandListener() @@ -459,7 +455,6 @@ def failed(event: CommandFailedEvent) -> None: self.assertEqual(len(started_finds), MAX_ADAPTIVE_RETRIES + 1) @client_context.require_failCommand_fail_point - @client_context.require_version_min(4, 4, 0) # type:ignore[untyped-decorator] def test_backoff_is_not_applied_for_non_overload_errors(self): if _IS_SYNC: mock_target = "pymongo.synchronous.helpers._RetryPolicy.backoff" diff --git a/test/test_retryable_writes.py b/test/test_retryable_writes.py index 577f9cbf0f..71552b208e 100644 --- a/test/test_retryable_writes.py +++ b/test/test_retryable_writes.py @@ -411,7 +411,6 @@ def setUp(self) -> None: }, } - @client_context.require_version_min(4, 0) @client_knobs(heartbeat_frequency=0.05, min_heartbeat_interval=0.05) def test_RetryableWriteError_error_label(self): listener = OvertCommandListener() @@ -429,7 +428,6 @@ def test_RetryableWriteError_error_label(self): # In MongoDB 4.4+ we rely on the server returning the error label. self.assertIn("RetryableWriteError", listener.succeeded_events[-1].reply["errorLabels"]) - @client_context.require_version_min(4, 4) def test_RetryableWriteError_error_label_RawBSONDocument(self): # using RawBSONDocument should not cause errorLabel parsing to fail with self.fail_point(self.fail_insert): diff --git a/test/test_sdam_monitoring_spec.py b/test/test_sdam_monitoring_spec.py index e2772b6306..437516999e 100644 --- a/test/test_sdam_monitoring_spec.py +++ b/test/test_sdam_monitoring_spec.py @@ -356,15 +356,6 @@ def marked_unknown_and_rediscovered(): def test_network_error_publishes_events(self): self._test_app_error({"closeConnection": True}, ConnectionFailure) - # In 4.4+, not primary errors from failCommand don't cause SDAM state - # changes because topologyVersion is not incremented. - @client_context.require_version_max(4, 3) - def test_not_primary_error_publishes_events(self): - self._test_app_error( - {"errorCode": 10107, "closeConnection": False, "errorLabels": ["RetryableWriteError"]}, - NotPrimaryError, - ) - def test_shutdown_error_publishes_events(self): self._test_app_error( {"errorCode": 91, "closeConnection": False, "errorLabels": ["RetryableWriteError"]}, diff --git a/test/test_topology.py b/test/test_topology.py index 47e670b20d..489c60f6b0 100644 --- a/test/test_topology.py +++ b/test/test_topology.py @@ -581,7 +581,7 @@ def test_wire_version(self): ) self.assertEqual(server.description.min_wire_version, 1) - self.assertEqual(server.description.max_wire_version, 8) + self.assertEqual(server.description.max_wire_version, common.MIN_SUPPORTED_WIRE_VERSION) t.select_servers(any_server_selector, _Op.TEST) # Incompatible. diff --git a/test/test_transactions.py b/test/test_transactions.py index c1a55af8ed..76163c3c12 100644 --- a/test/test_transactions.py +++ b/test/test_transactions.py @@ -135,14 +135,6 @@ def test_transaction_write_concern_override(self): (coll.drop_indexes, [], {}), (coll.aggregate, [[{"$out": "aggout"}]], {}), ] - # Creating a collection in a transaction requires MongoDB 4.4+. - if client_context.version < (4, 3, 4): - unsupported_txn_writes.extend( - [ - (db.create_collection, ["collection"], {}), - ] - ) - for op in unsupported_txn_writes: op, args, kwargs = op with client.start_session() as s: @@ -206,7 +198,6 @@ def test_unpin_for_non_transaction_operation(self): self.assertGreater(len(addresses), 1) @client_context.require_transactions - @client_context.require_version_min(4, 3, 4) def test_create_collection(self): client = client_context.client db = client.pymongo_test @@ -307,8 +298,6 @@ def gridfs_open_upload_stream(*args, **kwargs): ): op(*args, session=s) # type: ignore - # Require 4.2+ for large (16MB+) transactions. - @client_context.require_version_min(4, 2) @client_context.require_transactions @unittest.skipIf(sys.platform == "win32", "Our Windows machines are too slow to pass this test") def test_transaction_starts_with_batched_write(self):