55from enum import Enum
66from functools import partial , lru_cache
77from decimal import Decimal
8- from typing import Any , Never , get_args
8+ from typing import Any , Never , get_args , Iterable
99from typing_extensions import Self , Tuple
1010from pydantic import (PlainSerializer , PlainValidator , WrapValidator ,
1111 WrapSerializer )
1919RUNE_OBJ_MAPS = '__rune_object_maps'
2020
2121
22+ def _replaceable (prop ):
23+ return isinstance (prop , (BaseMetaDataMixin , UnresolvedReference , Reference ))
24+
25+
2226def _py_to_ser_key (key : str ) -> str :
2327 if key [0 ] == '@' :
2428 return key
@@ -203,8 +207,9 @@ def get_rune_parent(self) -> Self | None:
203207 def _get_meta_container (self ) -> dict [str , Any ]:
204208 return self .__dict__ .get (META_CONTAINER , {})
205209
206- def _merged_allowed_meta (self , allowed_meta : set [str ]) -> set [str ]:
207- default_meta = getattr (self , DEFAULT_META , set ())
210+ def _merged_allowed_meta (
211+ self , allowed_meta : set [str ] | Iterable [str ]) -> set [str ]:
212+ default_meta : set [str ] = getattr (self , DEFAULT_META , set ())
208213 return set (allowed_meta ) | default_meta
209214
210215 def _check_props_allowed (self , props : dict [str , Any ]):
@@ -231,9 +236,10 @@ def _init_meta(self, allowed_meta: set[str]):
231236
232237 def _bind_property_to (self , property_nm : str , ref : Reference ):
233238 '''set the property to reference the object referenced by the key'''
239+ old_val = getattr (self , property_nm )
234240 allowed_ref_types = getattr (self , '_KEY_REF_CONSTRAINTS' , {})
235- if ref .key_type .rune_ref_tag not in allowed_ref_types .get (
236- property_nm , {}):
241+ if ( ref .key_type .rune_ref_tag not in allowed_ref_types .get (
242+ property_nm , {}) and not _replaceable ( old_val )) :
237243 raise ValueError (f'Ref of type { ref .key_type } '
238244 f'not allowed for { property_nm } . Allowed types '
239245 f'are: { allowed_ref_types .get (property_nm , {})} ' )
@@ -245,18 +251,17 @@ def _bind_property_to(self, property_nm: str, ref: Reference):
245251 raise ValueError ("Can't set reference. Incompatible types: "
246252 f"expected { allowed_type } , "
247253 f"got { ref .target .__class__ } " )
254+
248255 refs = self .__dict__ .setdefault (REFS_CONTAINER , {})
249256 if property_nm not in refs :
250257 # not a reference - check if allowed to replace with one
251- old_val = getattr (self , property_nm )
252- if not isinstance (
253- old_val ,
254- (BaseMetaDataMixin , UnresolvedReference , Reference )):
258+ if not _replaceable (old_val ):
255259 raise ValueError (f'Property { property_nm } of type '
256260 f"{ type (old_val )} can't be a reference" )
257261 # pylint: disable=protected-access
258262 if isinstance (old_val , BaseMetaDataMixin ):
259263 old_val ._check_props_allowed ({ref .key_type .rune_ref_tag : '' })
264+
260265 # setattr(self, property_nm, ref.target) # nope - need to avoid here!
261266 self .__dict__ [property_nm ] = ref .target # NOTE: avoid here setattr
262267 refs [property_nm ] = (ref .target_key , ref .key_type )
0 commit comments