3131# _Entity class holds model information as well as conversions between python objects and FlatBuffers (ObjectBox data)
3232class _Entity (object ):
3333 def __init__ (self , user_type , uid : int = 0 ):
34- self .user_type = user_type
35- self .iduid = IdUid (0 , uid )
36- self .name = user_type .__name__
37- self .last_property_iduid = IdUid (0 , 0 )
38-
39- self .properties : List [Property ] = list () # List[Property]
40- self .offset_properties = list () # List[Property]
41- self .id_property = None
42- self .fill_properties ()
34+ self ._user_type = user_type
35+ self ._iduid = IdUid (0 , uid )
36+ self ._name = user_type .__name__
37+ self ._last_property_iduid = IdUid (0 , 0 )
38+
39+ self ._properties : List [Property ] = list () # List[Property]
40+ self ._offset_properties = list () # List[Property]
41+ self ._id_property = None
42+ self ._fill_properties ()
4343 self ._tl = threading .local ()
4444
4545 @property
46- def id (self ) -> int :
47- return self .iduid .id
46+ def _id (self ) -> int :
47+ return self ._iduid .id
4848
4949 @property
50- def uid (self ) -> int :
51- return self .iduid .uid
50+ def _uid (self ) -> int :
51+ return self ._iduid .uid
5252
53- def has_uid (self ) -> bool :
54- return self .iduid .uid != 0
53+ def _has_uid (self ) -> bool :
54+ return self ._iduid .uid != 0
5555
56- def on_sync (self ):
56+ def _on_sync (self ):
5757 """ Method called once ID/UID are synced with the model file. """
58- assert self .iduid .is_assigned ()
59- for prop in self .properties :
58+ assert self ._iduid .is_assigned ()
59+ for prop in self ._properties :
6060 prop .on_sync ()
6161
6262 def __call__ (self , ** properties ):
6363 """ The constructor of the user Entity class. """
64- object_ = self .user_type ()
64+ object_ = self ._user_type ()
6565 for prop_name , prop_val in properties .items ():
6666 if not hasattr (object_ , prop_name ):
67- raise Exception (f"Entity { self .name } has no property \" { prop_name } \" " )
67+ raise Exception (f"Entity { self ._name } has no property \" { prop_name } \" " )
6868 setattr (object_ , prop_name , prop_val )
6969 return object_
7070
71- def fill_properties (self ):
71+ def __getattr__ (self , name ):
72+ """ Overload to get properties via "<Entity>.<Prop>" notation. """
73+ for prop in self ._properties :
74+ if prop .name == name :
75+ return prop
76+ return self .__getattribute__ (name )
77+
78+ def _fill_properties (self ):
7279 # TODO allow subclassing and support entities with __slots__ defined
73- variables = dict (vars (self .user_type ))
80+ variables = dict (vars (self ._user_type ))
7481
7582 # filter only subclasses of Property
7683 variables = {k : v for k , v in variables .items (
7784 ) if issubclass (type (v ), Property )}
7885
7986 for prop_name , prop in variables .items ():
8087 prop .name = prop_name
81- self .properties .append (prop )
88+ self ._properties .append (prop )
8289
8390 if prop .is_id ():
84- if self .id_property :
85- raise Exception (f"Duplicate ID property: \" { self .id_property .name } \" and \" { prop .name } \" " )
86- self .id_property = prop
91+ if self ._id_property :
92+ raise Exception (f"Duplicate ID property: \" { self ._id_property .name } \" and \" { prop .name } \" " )
93+ self ._id_property = prop
8794
8895 if prop ._fb_type == flatbuffers .number_types .UOffsetTFlags :
8996 assert prop ._ob_type in [
@@ -98,34 +105,34 @@ def fill_properties(self):
98105 OBXPropertyType_DoubleVector ,
99106 OBXPropertyType_Flex ,
100107 ], "programming error - invalid type OB & FB type combination"
101- self .offset_properties .append (prop )
108+ self ._offset_properties .append (prop )
102109
103- # print('Property {}.{}: {} (ob:{} fb:{})'.format(self.name , prop.name, prop._py_type, prop._ob_type, prop._fb_type))
110+ # print('Property {}.{}: {} (ob:{} fb:{})'.format(self._name , prop.name, prop._py_type, prop._ob_type, prop._fb_type))
104111
105- if not self .id_property :
112+ if not self ._id_property :
106113 raise Exception ("ID property is not defined" )
107- elif self .id_property ._ob_type != OBXPropertyType_Long :
114+ elif self ._id_property ._ob_type != OBXPropertyType_Long :
108115 raise Exception ("ID property must be an int" )
109116
110- def get_property (self , name : str ):
117+ def _get_property (self , name : str ):
111118 """ Gets the property having the given name. """
112- for prop in self .properties :
119+ for prop in self ._properties :
113120 if prop .name == name :
114121 return prop
115- raise Exception (f"Property \" { name } \" not found in Entity: \" { self .name } \" " )
122+ raise Exception (f"Property \" { name } \" not found in Entity: \" { self ._name } \" " )
116123
117- def get_property_id (self , prop : Union [int , str , Property ]) -> int :
124+ def _get_property_id (self , prop : Union [int , str , Property ]) -> int :
118125 """ A convenient way to get the property ID regardless having its ID, name or Property. """
119126 if isinstance (prop , int ):
120127 return prop # We already have it!
121128 elif isinstance (prop , str ):
122- return self .get_property (prop ).id
129+ return self ._get_property (prop ).id
123130 elif isinstance (prop , Property ):
124131 return prop .id
125132 else :
126133 raise Exception (f"Unsupported Property type: { type (prop )} " )
127134
128- def get_value (self , object , prop : Property ):
135+ def _get_value (self , object , prop : Property ):
129136 # in case value is not overwritten on the object, it's the Property object itself (= as defined in the Class)
130137 val = getattr (object , prop .name )
131138 if prop ._py_type == np .ndarray :
@@ -140,22 +147,22 @@ def get_value(self, object, prop: Property):
140147 return prop ._py_type () # default (empty) value for the given type
141148 return val
142149
143- def get_object_id (self , obj ) -> int :
144- return self .get_value (obj , self .id_property )
150+ def _get_object_id (self , obj ) -> int :
151+ return self ._get_value (obj , self ._id_property )
145152
146- def set_object_id (self , obj , id_ : int ):
147- setattr (obj , self .id_property .name , id_ )
153+ def _set_object_id (self , obj , id_ : int ):
154+ setattr (obj , self ._id_property .name , id_ )
148155
149- def marshal (self , object , id : int ) -> bytearray :
156+ def _marshal (self , object , id : int ) -> bytearray :
150157 if not hasattr (self ._tl , "builder" ):
151158 self ._tl .builder = flatbuffers .Builder (256 )
152159 builder = self ._tl .builder
153160 builder .Clear ()
154161
155162 # prepare some properties that need to be built in FB before starting the main object
156163 offsets = {}
157- for prop in self .offset_properties :
158- val = self .get_value (object , prop )
164+ for prop in self ._offset_properties :
165+ val = self ._get_value (object , prop )
159166 if prop ._ob_type == OBXPropertyType_String :
160167 offsets [prop .id ] = builder .CreateString (val .encode ('utf-8' ))
161168 elif prop ._ob_type == OBXPropertyType_BoolVector :
@@ -185,17 +192,17 @@ def marshal(self, object, id: int) -> bytearray:
185192 assert False , "programming error - invalid type OB & FB type combination"
186193
187194 # start the FlatBuffers object with the largest number of properties that were ever present in the Entity
188- builder .StartObject (self .last_property_iduid .id )
195+ builder .StartObject (self ._last_property_iduid .id )
189196
190197 # add properties to the FB object
191- for prop in self .properties :
198+ for prop in self ._properties :
192199 prop_id = prop .id
193200 if prop_id in offsets :
194201 val = offsets [prop_id ]
195202 if val :
196203 builder .PrependUOffsetTRelative (val )
197204 else :
198- val = id if prop == self .id_property else self .get_value (object , prop )
205+ val = id if prop == self ._id_property else self ._get_value (object , prop )
199206 if prop ._ob_type == OBXPropertyType_Date :
200207 val = date_value_to_int (val , 1000 ) # convert to milliseconds
201208 elif prop ._ob_type == OBXPropertyType_DateNano :
@@ -207,15 +214,15 @@ def marshal(self, object, id: int) -> bytearray:
207214 builder .Finish (builder .EndObject ())
208215 return builder .Output ()
209216
210- def unmarshal (self , data : bytes ):
217+ def _unmarshal (self , data : bytes ):
211218 pos = flatbuffers .encode .Get (flatbuffers .packer .uoffset , data , 0 )
212219 table = flatbuffers .Table (data , pos )
213220
214221 # initialize an empty object
215- obj = self .user_type ()
222+ obj = self ._user_type ()
216223
217224 # fill it with the data read from FlatBuffers
218- for prop in self .properties :
225+ for prop in self ._properties :
219226 o = table .Offset (prop ._fb_v_offset )
220227 val = None
221228 ob_type = prop ._ob_type
0 commit comments