diff --git a/.evergreen/generated_configs/tasks.yml b/.evergreen/generated_configs/tasks.yml index 8064ec85e..855cbefef 100644 --- a/.evergreen/generated_configs/tasks.yml +++ b/.evergreen/generated_configs/tasks.yml @@ -4766,3 +4766,351 @@ tasks: - standalone-noauth-nossl - noauth - pypy + + # Test standard auth tests + - name: test-standard-auth-v4.2-python3.10-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" + PYTHON_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.10-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" + PYTHON_VERSION: pypy3.10 + tags: + - test-standard-auth + - server-4.2 + - python-pypy3.10 + - 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" + PYTHON_VERSION: "3.11" + tags: + - test-standard-auth + - server-4.4 + - python-3.11 + - sharded_cluster-auth-ssl + - auth + - name: test-standard-auth-v4.4-pypy3.10-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" + PYTHON_VERSION: pypy3.10 + tags: + - test-standard-auth + - server-4.4 + - python-pypy3.10 + - sharded_cluster-auth-ssl + - auth + - pypy + - name: test-standard-auth-v5.0-python3.12-auth-ssl-sharded-cluster + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: "5.0" + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: "5.0" + PYTHON_VERSION: "3.12" + tags: + - test-standard-auth + - server-5.0 + - python-3.12 + - sharded_cluster-auth-ssl + - auth + - name: test-standard-auth-v5.0-pypy3.10-auth-ssl-sharded-cluster + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: "5.0" + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: "5.0" + PYTHON_VERSION: pypy3.10 + tags: + - test-standard-auth + - server-5.0 + - python-pypy3.10 + - sharded_cluster-auth-ssl + - auth + - pypy + - name: test-standard-auth-v6.0-python3.13-auth-ssl-sharded-cluster + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: "6.0" + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: "6.0" + PYTHON_VERSION: "3.13" + tags: + - test-standard-auth + - server-6.0 + - python-3.13 + - sharded_cluster-auth-ssl + - auth + - name: test-standard-auth-v6.0-pypy3.10-auth-ssl-sharded-cluster + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: "6.0" + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: "6.0" + PYTHON_VERSION: pypy3.10 + tags: + - test-standard-auth + - server-6.0 + - python-pypy3.10 + - sharded_cluster-auth-ssl + - auth + - pypy + - name: test-standard-auth-v7.0-python3.14t-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" + PYTHON_VERSION: 3.14t + tags: + - test-standard-auth + - server-7.0 + - python-3.14t + - sharded_cluster-auth-ssl + - auth + - free-threaded + - name: test-standard-auth-v7.0-pypy3.10-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" + PYTHON_VERSION: pypy3.10 + tags: + - test-standard-auth + - server-7.0 + - python-pypy3.10 + - sharded_cluster-auth-ssl + - auth + - pypy + - name: test-standard-auth-v8.0-python3.14-auth-ssl-sharded-cluster + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: "8.0" + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: "8.0" + PYTHON_VERSION: "3.14" + tags: + - test-standard-auth + - server-8.0 + - python-3.14 + - sharded_cluster-auth-ssl + - auth + - name: test-standard-auth-v8.0-pypy3.10-auth-ssl-sharded-cluster + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: "8.0" + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: "8.0" + PYTHON_VERSION: pypy3.10 + tags: + - test-standard-auth + - server-8.0 + - python-pypy3.10 + - sharded_cluster-auth-ssl + - auth + - pypy + - name: test-standard-auth-latest-python3.11-auth-ssl-sharded-cluster + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: latest + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: latest + PYTHON_VERSION: "3.11" + tags: + - test-standard-auth + - server-latest + - python-3.11 + - sharded_cluster-auth-ssl + - auth + - pr + - name: test-standard-auth-latest-pypy3.10-auth-ssl-sharded-cluster + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: latest + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: latest + PYTHON_VERSION: pypy3.10 + tags: + - test-standard-auth + - server-latest + - python-pypy3.10 + - sharded_cluster-auth-ssl + - auth + - pypy + - name: test-standard-auth-rapid-python3.10-auth-ssl-sharded-cluster + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: rapid + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: rapid + PYTHON_VERSION: "3.10" + tags: + - test-standard-auth + - server-rapid + - python-3.10 + - sharded_cluster-auth-ssl + - auth + - name: test-standard-auth-rapid-pypy3.10-auth-ssl-sharded-cluster + commands: + - func: run server + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: rapid + - func: run tests + vars: + AUTH: auth + SSL: ssl + TOPOLOGY: sharded_cluster + VERSION: rapid + PYTHON_VERSION: pypy3.10 + tags: + - test-standard-auth + - server-rapid + - python-pypy3.10 + - sharded_cluster-auth-ssl + - auth + - pypy diff --git a/.evergreen/generated_configs/variants.yml b/.evergreen/generated_configs/variants.yml index acdbd0dca..aae221adf 100644 --- a/.evergreen/generated_configs/variants.yml +++ b/.evergreen/generated_configs/variants.yml @@ -9,6 +9,7 @@ buildvariants: batchtime: 1440 expansions: VERSION: latest + PYTHON_BINARY: /usr/bin/python3.11 NO_EXT: "1" REQUIRE_FIPS: "1" tags: [] @@ -21,6 +22,7 @@ buildvariants: batchtime: 1440 expansions: VERSION: latest + PYTHON_BINARY: /usr/bin/python3.11 NO_EXT: "1" tags: [] - name: other-hosts-rhel8-power8-latest @@ -32,6 +34,7 @@ buildvariants: batchtime: 1440 expansions: VERSION: latest + PYTHON_BINARY: /usr/bin/python3.11 NO_EXT: "1" tags: [] - name: other-hosts-rhel8-arm64-latest @@ -43,6 +46,7 @@ buildvariants: batchtime: 1440 expansions: VERSION: latest + PYTHON_BINARY: /usr/bin/python3.11 NO_EXT: "1" tags: [] - name: other-hosts-amazon2023-latest @@ -54,6 +58,7 @@ buildvariants: batchtime: 1440 expansions: VERSION: latest + PYTHON_BINARY: /usr/bin/python3.11 NO_EXT: "1" tags: [pr] @@ -71,7 +76,7 @@ buildvariants: # Aws auth tests - name: auth-aws-ubuntu-20 tasks: - - name: .auth-aws + - name: .auth-aws !.auth-aws-ecs display_name: Auth AWS Ubuntu-20 run_on: - ubuntu2004-small @@ -244,7 +249,7 @@ buildvariants: # Enterprise auth tests - name: auth-enterprise-rhel8 tasks: - - name: .test-non-standard .auth !.free-threaded + - name: .test-standard-auth .auth !.free-threaded display_name: Auth Enterprise RHEL8 run_on: - rhel87-small @@ -253,7 +258,7 @@ buildvariants: AUTH: auth - name: auth-enterprise-macos tasks: - - name: .test-non-standard !.pypy .auth !.free-threaded + - name: .test-standard-auth !.pypy .auth !.free-threaded display_name: Auth Enterprise macOS run_on: - macos-14 @@ -262,7 +267,7 @@ buildvariants: AUTH: auth - name: auth-enterprise-win64 tasks: - - name: .test-non-standard !.pypy .auth + - name: .test-standard-auth !.pypy .auth display_name: Auth Enterprise Win64 run_on: - windows-64-vsMulti-small diff --git a/.evergreen/scripts/generate_config.py b/.evergreen/scripts/generate_config.py index 203f28830..7f199d148 100644 --- a/.evergreen/scripts/generate_config.py +++ b/.evergreen/scripts/generate_config.py @@ -202,12 +202,12 @@ def create_enterprise_auth_variants(): for host in ["rhel8", "macos", "win64"]: expansions = dict(TEST_NAME="enterprise_auth", AUTH="auth") display_name = get_variant_name("Auth Enterprise", host) - tasks = [".test-non-standard .auth !.free-threaded"] + tasks = [".test-standard-auth .auth !.free-threaded"] # https://jira.mongodb.org/browse/PYTHON-5586 if host == "macos": - tasks = [".test-non-standard !.pypy .auth !.free-threaded"] + tasks = [".test-standard-auth !.pypy .auth !.free-threaded"] if host == "win64": - tasks = [".test-non-standard !.pypy .auth"] + tasks = [".test-standard-auth !.pypy .auth"] variant = create_variant(tasks, display_name, host=host, expansions=expansions) variants.append(variant) return variants @@ -438,7 +438,8 @@ def create_aws_auth_variants(): for host_name in ["ubuntu20", "win64", "macos"]: expansions = dict() - tasks = [".auth-aws"] + # PYTHON-5604 - we need to skip ECS tests for now. + tasks = [".auth-aws !.auth-aws-ecs"] tags = [] if host_name == "macos": tasks = [".auth-aws !.auth-aws-web-identity !.auth-aws-ecs !.auth-aws-ec2"] @@ -469,7 +470,8 @@ def create_alternative_hosts_variants(): version = "latest" for host_name in OTHER_HOSTS: - expansions = dict(VERSION="latest") + # Use explicit Python 3.11 binary on the host since the default python3 is 3.9. + expansions = dict(VERSION="latest", PYTHON_BINARY="/usr/bin/python3.11") handle_c_ext(C_EXTS[0], expansions) host = HOSTS[host_name] tags = [] @@ -574,7 +576,7 @@ def create_test_non_standard_tasks(): for (version, topology), python in zip_cycle(list(product(ALL_VERSIONS, TOPOLOGIES)), CPYTHONS): pr = version == "latest" task_combos.add((version, topology, python, pr)) - # For each PyPy and topology, rotate through the the versions. + # For each PyPy and topology, rotate through the MongoDB versions. for (python, topology), version in zip_cycle(list(product(PYPYS, TOPOLOGIES)), ALL_VERSIONS): task_combos.add((version, topology, python, False)) for version, topology, python, pr in sorted(task_combos): @@ -602,6 +604,46 @@ def create_test_non_standard_tasks(): return tasks +def create_test_standard_auth_tasks(): + """We only use auth on sharded clusters""" + tasks = [] + task_combos = set() + # Rotate through the CPython and MongoDB versions + for (version, topology), python in zip_cycle( + list(product(ALL_VERSIONS, ["sharded_cluster"])), CPYTHONS + ): + pr = version == "latest" + task_combos.add((version, topology, python, pr)) + # Rotate through each PyPy and MongoDB versions. + for (python, topology), version in zip_cycle( + list(product(PYPYS, ["sharded_cluster"])), ALL_VERSIONS + ): + task_combos.add((version, topology, python, False)) + for version, topology, python, pr in sorted(task_combos): + auth, ssl = get_standard_auth_ssl(topology) + tags = [ + "test-standard-auth", + f"server-{version}", + f"python-{python}", + f"{topology}-{auth}-{ssl}", + auth, + ] + if "t" in python: + tags.append("free-threaded") + if python in PYPYS: + tags.append("pypy") + if pr: + tags.append("pr") + expansions = dict(AUTH=auth, SSL=ssl, TOPOLOGY=topology, VERSION=version) + name = get_task_name("test-standard-auth", python=python, **expansions) + server_func = FunctionCall(func="run server", vars=expansions) + test_vars = expansions.copy() + test_vars["PYTHON_VERSION"] = python + test_func = FunctionCall(func="run tests", vars=test_vars) + tasks.append(EvgTask(name=name, tags=tags, commands=[server_func, test_func])) + return tasks + + def create_min_deps_tasks(): """For variants that support testing with minimum dependencies.""" tasks = [] diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..8185a3883 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,38 @@ + + +[Issue Key](https://jira.mongodb.org/browse/%7BISSUE_KEY%7D) +## Summary + + +## Changes in this PR + + +## Testing Plan + + +### Screenshots (optional) + + +## Checklist + +### Checklist for Author +- [ ] Did you update the changelog (if necessary)? +- [ ] Is the intention of the code captured in relevant tests? +- [ ] If there are new TODOs, has a related JIRA ticket been created? + +### Checklist for Reviewer {@primary_reviewer} +- [ ] Does the title of the PR reference a JIRA Ticket? +- [ ] Do you fully understand the implementation? (Would you be comfortable explaining how this code works to someone else?) +- [ ] Have you checked for spelling & grammar errors? +- [ ] Is all relevant documentation (README or docstring) updated? + +## Focus Areas for Reviewer (optional) + diff --git a/.github/workflows/pull_request_template.md b/.github/workflows/pull_request_template.md deleted file mode 100644 index 852066d4b..000000000 --- a/.github/workflows/pull_request_template.md +++ /dev/null @@ -1,23 +0,0 @@ -# [JIRA Ticket ID](Link to Ticket) - - -# Summary - - -# Changes in this PR - - -# Test Plan - - -# Screenshots (Optional) - - -# Callouts or Follow-up items (Optional) - diff --git a/justfile b/justfile index f23534616..17b95e87b 100644 --- a/justfile +++ b/justfile @@ -58,7 +58,7 @@ lint-manual *args="": && resync [group('test')] test *args="-v --durations=5 --maxfail=10": && resync - uvx --extra test pytest {{args}} + uv run --extra test pytest {{args}} [group('test')] run-tests *args: && resync diff --git a/pymongo/asynchronous/collection.py b/pymongo/asynchronous/collection.py index 6af1f4f78..e7e2f5803 100644 --- a/pymongo/asynchronous/collection.py +++ b/pymongo/asynchronous/collection.py @@ -3143,7 +3143,7 @@ class AsyncCollection(common.BaseObject, Generic[_DocumentType]): comment: Optional[Any] = None, hint: Optional[_IndexKeyHint] = None, **kwargs: Any, - ) -> list[str]: + ) -> list[Any]: """Get a list of distinct values for `key` among all documents in this collection. diff --git a/pymongo/asynchronous/cursor.py b/pymongo/asynchronous/cursor.py index cf3a5372b..f19d3f6ce 100644 --- a/pymongo/asynchronous/cursor.py +++ b/pymongo/asynchronous/cursor.py @@ -1063,7 +1063,7 @@ class AsyncCursor(Generic[_DocumentType]): """Explicitly close / kill this cursor.""" await self._die_lock() - async def distinct(self, key: str) -> list[str]: + async def distinct(self, key: str) -> list[Any]: """Get a list of distinct values for `key` among all documents in the result set of this query. diff --git a/pymongo/synchronous/collection.py b/pymongo/synchronous/collection.py index b68e4befe..4e5f7d08f 100644 --- a/pymongo/synchronous/collection.py +++ b/pymongo/synchronous/collection.py @@ -3136,7 +3136,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]): comment: Optional[Any] = None, hint: Optional[_IndexKeyHint] = None, **kwargs: Any, - ) -> list[str]: + ) -> list[Any]: """Get a list of distinct values for `key` among all documents in this collection. diff --git a/pymongo/synchronous/cursor.py b/pymongo/synchronous/cursor.py index 12e2863bc..fcd8ebeb1 100644 --- a/pymongo/synchronous/cursor.py +++ b/pymongo/synchronous/cursor.py @@ -1061,7 +1061,7 @@ class Cursor(Generic[_DocumentType]): """Explicitly close / kill this cursor.""" self._die_lock() - def distinct(self, key: str) -> list[str]: + def distinct(self, key: str) -> list[Any]: """Get a list of distinct values for `key` among all documents in the result set of this query. diff --git a/test/test_typing.py b/test/test_typing.py index 7240e59c0..17dc21b4e 100644 --- a/test/test_typing.py +++ b/test/test_typing.py @@ -69,7 +69,7 @@ sys.path[0:0] = [""] from test import IntegrationTest, PyMongoTestCase, client_context -from bson import CodecOptions, decode, decode_all, decode_file_iter, decode_iter, encode +from bson import CodecOptions, ObjectId, decode, decode_all, decode_file_iter, decode_iter, encode from bson.raw_bson import RawBSONDocument from bson.son import SON from pymongo import ASCENDING, MongoClient @@ -141,6 +141,32 @@ class TestPymongo(IntegrationTest): docs = to_list(cursor) self.assertTrue(docs) + def test_distinct(self) -> None: + self.coll.delete_many({}) + self.coll.insert_many( + [ + {"_id": None}, + {"_id": 0}, + {"_id": ""}, + {"_id": ObjectId()}, + {"_id": True}, + ] + ) + + def collection_distinct( + collection: Collection, + ) -> list[None | int | str | ObjectId | bool]: + return collection.distinct("_id") + + def cursor_distinct( + collection: Collection, + ) -> list[None | int | str | ObjectId | bool]: + cursor = collection.find() + return cursor.distinct("_id") + + collection_distinct(self.coll) + cursor_distinct(self.coll) + @only_type_check def test_bulk_write(self) -> None: self.coll.insert_one({})