-
Type:
Bug
-
Resolution: Unresolved
-
Priority:
Major - P3
-
None
-
Affects Version/s: None
-
Component/s: None
-
None
-
Python Drivers
-
None
-
None
-
None
-
None
-
None
-
None
PyMongo 4.18.1 and 4.18.2 / CPython 3.14.6 / mypy 2.3.1. No MongoDB server is needed.
Both native cursor constructors declare `let: Optional[bool] = None`. Their implementations call `validate_is_document_type("let", let)` for any non-None value. A document constructs successfully; a boolean raises TypeError at construction. Mypy reports two arg-type errors for document arguments and accepts the boolean arguments.
The affected released source is [Cursor](https://github.com/mongodb/mongo-python-driver/blob/640dd2383a1a2fb1a10e5222d50ebc0b22a61bd7/pymongo/synchronous/cursor.py#L97) and [AsyncCursor](https://github.com/mongodb/mongo-python-driver/blob/640dd2383a1a2fb1a10e5222d50ebc0b22a61bd7/pymongo/asynchronous/cursor.py#L97). The same files are byte-identical in the selected 4.18.1 source archive.
This report concerns constructor annotations and generated API documentation. Application code normally obtains cursors from `Collection.find` / `AsyncCollection.find`; those methods use variadic Any arguments, so their callers do not receive this particular static error. Native runtime forwarding of `let` remains usable. No claim of adapter incompatibility follows from this mismatch.
Save this as `let_typing.py`:
```python
from pymongo.asynchronous.collection import AsyncCollection
from pymongo.asynchronous.cursor import AsyncCursor
from pymongo.synchronous.collection import Collection
from pymongo.synchronous.cursor import Cursor
def sync_document(collection: Collection[dict[str, int]]) -> Cursor[dict[str, int]]:
return Cursor(collection, let={"threshold": 1})
def async_document(
collection: AsyncCollection[dict[str, int]],
) -> AsyncCursor[dict[str, int]]:
return AsyncCursor(collection, let={"threshold": 1})
def sync_bool(collection: Collection[dict[str, int]]) -> Cursor[dict[str, int]]:
return Cursor(collection, let=True)
def async_bool(
collection: AsyncCollection[dict[str, int]],
) -> AsyncCursor[dict[str, int]]:
return AsyncCursor(collection, let=True)
```
Save this adjacent file as `let_runtime.py`:
```python
import asyncio
import pymongo
from pymongo import AsyncMongoClient, MongoClient
from let_typing import async_bool, async_document, sync_bool, sync_document
def check(collection, make_document, make_bool):
cursor = make_document(collection)
try:
make_bool(collection)
except TypeError as error:
print(type(cursor)._name_, 'document accepted; bool rejected:', str(error))
else:
raise AssertionError('Boolean let unexpectedly accepted')
return cursor
def synchronous():
with MongoClient[dict[str, int]](connect=False) as client:
cursor = check(client['let_annotation']['records'], sync_document, sync_bool)
cursor.close()
async def asynchronous():
async with AsyncMongoClient[dict[str, int]](connect=False) as client:
cursor = check(client['let_annotation']['records'], async_document, async_bool)
await cursor.close()
if _name_ == '_main_':
print('PyMongo', pymongo.version)
synchronous()
asyncio.run(asynchronous())
```
Run in this project's existing environment (or an environment with the stated PyMongo and mypy versions):
```bash
uv run --frozen --no-sync mypy --no-incremental --follow-imports=silent /tmp/cqc-adapter-study-20261004/let_typing.py
uv run --frozen --no-sync python /tmp/cqc-adapter-study-20261004/let_runtime.py
uv run --frozen --no-sync --with pymongo==4.18.1 mypy --no-incremental --follow-imports=silent /tmp/cqc-adapter-study-20261004/let_typing.py
uv run --frozen --no-sync --with pymongo==4.18.1 python /tmp/cqc-adapter-study-20261004/let_runtime.py
```
Both mypy commands exit 1 with exactly two `arg-type` errors: the document is incompatible with `bool | None`. Both runtime commands exit 0 and report document acceptance and boolean rejection for sync and async constructors. Clients use `connect=False`; cursors are never consumed, and all handles are closed.
Expected: annotate `let` with the document forms accepted by native validation, matching the documented map-of-parameters behavior and preserving None.