1
+ # mypy: disable-error-code="attr-defined,union-attr,assignment"
2
+ from __future__ import annotations
3
+
1
4
import copy
2
5
import numbers
3
6
import warnings
4
7
from functools import partial
8
+ from typing import TYPE_CHECKING , Any
5
9
6
10
import pymongo
7
11
from bson import SON , DBRef , ObjectId , json_util
12
+ from typing_extensions import Self
8
13
9
14
from mongoengine import signals
10
15
from mongoengine .base .common import _DocumentRegistry
15
20
LazyReference ,
16
21
StrictDict ,
17
22
)
18
- from mongoengine .base .fields import ComplexBaseField
23
+ from mongoengine .base .fields import BaseField , ComplexBaseField
19
24
from mongoengine .common import _import_class
20
25
from mongoengine .errors import (
21
26
FieldDoesNotExist ,
26
31
)
27
32
from mongoengine .pymongo_support import LEGACY_JSON_OPTIONS
28
33
34
+ if TYPE_CHECKING :
35
+ from mongoengine .fields import DynamicField
36
+
29
37
__all__ = ("BaseDocument" , "NON_FIELD_ERRORS" )
30
38
31
39
NON_FIELD_ERRORS = "__all__"
32
40
33
41
try :
34
- GEOHAYSTACK = pymongo .GEOHAYSTACK
42
+ GEOHAYSTACK = pymongo .GEOHAYSTACK # type: ignore[attr-defined]
35
43
except AttributeError :
36
44
GEOHAYSTACK = None
37
45
@@ -62,7 +70,12 @@ class BaseDocument:
62
70
_dynamic_lock = True
63
71
STRICT = False
64
72
65
- def __init__ (self , * args , ** values ):
73
+ # Fields, added by metaclass
74
+ _class_name : str
75
+ _fields : dict [str , BaseField ]
76
+ _meta : dict [str , Any ]
77
+
78
+ def __init__ (self , * args , ** values ) -> None :
66
79
"""
67
80
Initialise a document or an embedded document.
68
81
@@ -103,7 +116,7 @@ def __init__(self, *args, **values):
103
116
else :
104
117
self ._data = {}
105
118
106
- self ._dynamic_fields = SON ()
119
+ self ._dynamic_fields : SON [ str , DynamicField ] = SON ()
107
120
108
121
# Assign default values for fields
109
122
# not set in the constructor
@@ -329,13 +342,15 @@ def get_text_score(self):
329
342
330
343
return self ._data ["_text_score" ]
331
344
332
- def to_mongo (self , use_db_field = True , fields = None ):
345
+ def to_mongo (
346
+ self , use_db_field : bool = True , fields : list [str ] | None = None
347
+ ) -> SON [Any , Any ]:
333
348
"""
334
349
Return as SON data ready for use with MongoDB.
335
350
"""
336
351
fields = fields or []
337
352
338
- data = SON ()
353
+ data : SON [ str , Any ] = SON ()
339
354
data ["_id" ] = None
340
355
data ["_cls" ] = self ._class_name
341
356
@@ -354,7 +369,7 @@ def to_mongo(self, use_db_field=True, fields=None):
354
369
355
370
if value is not None :
356
371
f_inputs = field .to_mongo .__code__ .co_varnames
357
- ex_vars = {}
372
+ ex_vars : dict [ str , Any ] = {}
358
373
if fields and "fields" in f_inputs :
359
374
key = "%s." % field_name
360
375
embedded_fields = [
@@ -370,7 +385,7 @@ def to_mongo(self, use_db_field=True, fields=None):
370
385
371
386
# Handle self generating fields
372
387
if value is None and field ._auto_gen :
373
- value = field .generate ()
388
+ value = field .generate () # type: ignore[attr-defined]
374
389
self ._data [field_name ] = value
375
390
376
391
if value is not None or field .null :
@@ -385,7 +400,7 @@ def to_mongo(self, use_db_field=True, fields=None):
385
400
386
401
return data
387
402
388
- def validate (self , clean = True ):
403
+ def validate (self , clean : bool = True ) -> None :
389
404
"""Ensure that all fields' values are valid and that required fields
390
405
are present.
391
406
@@ -439,7 +454,7 @@ def validate(self, clean=True):
439
454
message = f"ValidationError ({ self ._class_name } :{ pk } ) "
440
455
raise ValidationError (message , errors = errors )
441
456
442
- def to_json (self , * args , ** kwargs ) :
457
+ def to_json (self , * args : Any , ** kwargs : Any ) -> str :
443
458
"""Convert this document to JSON.
444
459
445
460
:param use_db_field: Serialize field names as they appear in
@@ -461,7 +476,7 @@ def to_json(self, *args, **kwargs):
461
476
return json_util .dumps (self .to_mongo (use_db_field ), * args , ** kwargs )
462
477
463
478
@classmethod
464
- def from_json (cls , json_data , created = False , ** kwargs ) :
479
+ def from_json (cls , json_data : str , created : bool = False , ** kwargs : Any ) -> Self :
465
480
"""Converts json data to a Document instance.
466
481
467
482
:param str json_data: The json data to load into the Document.
@@ -687,7 +702,7 @@ def _get_changed_fields(self):
687
702
self ._nestable_types_changed_fields (changed_fields , key , data )
688
703
return changed_fields
689
704
690
- def _delta (self ):
705
+ def _delta (self ) -> tuple [ dict [ str , Any ], dict [ str , Any ]] :
691
706
"""Returns the delta (set, unset) of the changes for a document.
692
707
Gets any values that have been explicitly changed.
693
708
"""
@@ -771,14 +786,16 @@ def _delta(self):
771
786
return set_data , unset_data
772
787
773
788
@classmethod
774
- def _get_collection_name (cls ):
789
+ def _get_collection_name (cls ) -> str | None :
775
790
"""Return the collection name for this class. None for abstract
776
791
class.
777
792
"""
778
793
return cls ._meta .get ("collection" , None )
779
794
780
795
@classmethod
781
- def _from_son (cls , son , _auto_dereference = True , created = False ):
796
+ def _from_son (
797
+ cls , son : dict [str , Any ], _auto_dereference : bool = True , created : bool = False
798
+ ) -> Self :
782
799
"""Create an instance of a Document (subclass) from a PyMongo SON (dict)"""
783
800
if son and not isinstance (son , dict ):
784
801
raise ValueError (
0 commit comments