17
17
18
18
from datetime import date , datetime
19
19
from fnmatch import fnmatch
20
+ from typing import List , Optional
20
21
21
22
from .exceptions import ValidationException
22
- from .field import Field , Integer , Float , Boolean , Text , Binary , Date
23
+ from .field import (
24
+ Binary ,
25
+ Boolean ,
26
+ Date ,
27
+ Field ,
28
+ Float ,
29
+ InstrumentedField ,
30
+ Integer ,
31
+ Nested ,
32
+ Object ,
33
+ Text ,
34
+ )
23
35
from .mapping import Mapping
24
36
from .utils import DOC_META_FIELDS , ObjectBase
25
37
@@ -35,6 +47,11 @@ def __new__(cls, name, bases, attrs):
35
47
attrs ["_doc_type" ] = DocumentOptions (name , bases , attrs )
36
48
return super ().__new__ (cls , name , bases , attrs )
37
49
50
+ def __getattr__ (cls , attr ):
51
+ if attr in cls ._doc_type .mapping :
52
+ return InstrumentedField (attr , cls ._doc_type .mapping [attr ])
53
+ return super ().__getattribute__ (attr )
54
+
38
55
39
56
class DocumentOptions :
40
57
type_annotation_map = {
@@ -53,18 +70,38 @@ def __init__(self, name, bases, attrs):
53
70
# create the mapping instance
54
71
self .mapping = getattr (meta , "mapping" , Mapping ())
55
72
56
- for name , type_ in attrs .get ('__annotations__' , {}).items ():
57
- if name not in attrs :
58
- if type_ in self .type_annotation_map :
73
+ annotations = attrs .get ("__annotations__" , {})
74
+ fields = set ([n for n in attrs if isinstance (attrs [n ], Field )])
75
+ fields .update (annotations .keys ())
76
+ for name in fields :
77
+ if name in attrs :
78
+ value = attrs [name ]
79
+ else :
80
+ type_ = annotations [name ]
81
+ required = True
82
+ multi = False
83
+ while hasattr (type_ , "__origin__" ):
84
+ if type_ .__origin__ == Optional :
85
+ required = False
86
+ type_ = type_ .__args__ [0 ]
87
+ elif issubclass (type_ .__origin__ , List ):
88
+ multi = True
89
+ type_ = type_ .__args__ [0 ]
90
+ if issubclass (type_ , InnerDoc ):
91
+ field = Nested if multi else Object
92
+ field_args = {}
93
+ elif type_ in self .type_annotation_map :
59
94
field , field_args = self .type_annotation_map [type_ ]
60
- self .mapping .field (name , field (** field_args ))
61
- elif issubclass (type_ , Field ):
62
- self .mapping .field (name , type_ ())
63
-
64
- # register all declared fields into the mapping
65
- for name , value in list (attrs .items ()):
66
- if isinstance (value , Field ):
67
- self .mapping .field (name , value )
95
+ elif not issubclass (type_ , Field ):
96
+ raise TypeError (f"Cannot map type { type_ } " )
97
+ else :
98
+ field = type_
99
+ field_args = {}
100
+ field_args = {"multi" : multi , "required" : required , ** field_args }
101
+ value = field (** field_args )
102
+ value ._name = name
103
+ self .mapping .field (name , value )
104
+ if name in attrs :
68
105
del attrs [name ]
69
106
70
107
# add all the mappings for meta fields
0 commit comments