Skip to content

Commit 2a86839

Browse files
committed
fix test
1 parent 6e21760 commit 2a86839

File tree

2 files changed

+21
-9
lines changed

2 files changed

+21
-9
lines changed

doc/examples/type_hints.rst

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,20 @@ Note that when using :class:`~bson.son.SON`, the key and value types must be giv
9292
Typed Collection
9393
----------------
9494

95-
You can use :py:class:`~typing.TypedDict` (Python 3.8+) when using a well-defined schema for the data in a :class:`~pymongo.collection.Collection`.
95+
You can use :py:class:`~typing_extensions.TypedDict` (Python 3.8+) when using a well-defined schema for the data in a :class:`~pymongo.collection.Collection`.
9696
Note that all `schema_validation`_ for inserts and updates is done on the server. This is due to the fact that these methods automatically add
97-
an "_id" field. Do not rely on TypedDicts for schema validation, only for providing a more ergonomic interface:
97+
an "_id" field. The "_id" field is decorated by :py:class:`~typing_extensions.NotRequired` decorator to allow it to be accessed when reading
98+
from `result` (albeit without type-checking for that specific field, hence why it should not be used for schema validation).
99+
Another option would be to generate the "_id" field yourself, and make it a required field, which would give the expected behavior.
98100

99101
.. doctest::
100102

101-
>>> from typing import TypedDict
103+
>>> from typing_extensions import TypedDict, NotRequired
102104
>>> from pymongo import MongoClient
103105
>>> from pymongo.collection import Collection
106+
>>> from bson import ObjectId
104107
>>> class Movie(TypedDict):
108+
... _id: NotRequired[ObjectId]
105109
... name: str
106110
... year: int
107111
...
@@ -111,6 +115,8 @@ an "_id" field. Do not rely on TypedDicts for schema validation, only for provid
111115
>>> result = collection.find_one({"name": "Jurassic Park"})
112116
>>> assert result is not None
113117
>>> assert result["year"] == 1993
118+
>>> # Mypy will not check this because it is NotRequired
119+
>>> assert result["_id"] == tuple()
114120

115121
Typed Database
116122
--------------

test/test_mypy.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,14 @@
2121
from typing import TYPE_CHECKING, Any, Dict, Iterable, Iterator, List, Optional
2222

2323
try:
24-
from typing import TypedDict # type: ignore[attr-defined]
24+
from typing_extensions import NotRequired, TypedDict
25+
26+
from bson import ObjectId
2527

2628
# Not available in Python 3.7
2729
class Movie(TypedDict): # type: ignore[misc]
30+
_id: ObjectId
31+
idiot: ObjectId
2832
name: str
2933
year: int
3034

@@ -312,16 +316,18 @@ def test_typeddict_document_type(self) -> None:
312316
assert retreived["year"] == 1
313317
assert retreived["name"] == "a"
314318

319+
# TODO: mypy --install-types --non-interactive test/test_mypy.py
320+
# run just this file in CI
315321
@only_type_check
316322
def test_typeddict_document_type_insertion(self) -> None:
317323
client: MongoClient[Movie] = MongoClient()
318324
coll: Collection[Movie] = client.test.test
319-
insert = coll.insert_one(Movie(name="THX-1138", year=1971))
320-
out: Optional[Movie] = coll.find_one({"name": "THX-1138"})
325+
insert = coll.insert_one(Movie(_id=ObjectId(), name="THX-1138", year=1971))
326+
out = coll.find_one({"name": "THX-1138"})
321327
assert out is not None
322-
assert out.name == "THX-1138"
323-
assert out.year == "1971"
324-
assert out.id == ObjectId()
328+
# This should fail because the output is a Movie.
329+
assert out["foo"] # type:ignore[typeddict-item]
330+
assert type(out["_id"]) == ObjectId
325331

326332
@only_type_check
327333
def test_raw_bson_document_type(self) -> None:

0 commit comments

Comments
 (0)