@@ -105,7 +105,7 @@ class Resource(ABC):
105
105
# TODO: Make `Resource` an abstract class and not giving `resource_type`/`property_types` initial value.
106
106
resource_type : str = None # type: ignore
107
107
property_types : Dict [str , PropertyType ] = None # type: ignore
108
- _keywords = [ "logical_id" , "relative_id" , "depends_on" , "resource_attributes" ]
108
+ _keywords = { "logical_id" , "relative_id" , "depends_on" , "resource_attributes" }
109
109
110
110
# For attributes in this list, they will be passed into the translated template for the same resource itself.
111
111
_supported_resource_attributes = ["DeletionPolicy" , "UpdatePolicy" , "Condition" , "UpdateReplacePolicy" , "Metadata" ]
@@ -122,6 +122,11 @@ class Resource(ABC):
122
122
# }
123
123
runtime_attrs : Dict [str , Callable [["Resource" ], Any ]] = {} # TODO: replace Any with something more explicit
124
124
125
+ # When "validate_setattr" is True, we cannot change the value of any class variables after instantiation unless they
126
+ # are in "property_types" or "_keywords". We can set this to False in the inheriting class definition so we can
127
+ # update other class variables as well after instantiation.
128
+ validate_setattr : bool = True
129
+
125
130
def __init__ (
126
131
self ,
127
132
logical_id : Optional [Any ],
@@ -313,7 +318,7 @@ def __setattr__(self, name, value): # type: ignore[no-untyped-def]
313
318
:param value: the value of the attribute to be set
314
319
:raises InvalidResourceException: if an invalid property is provided
315
320
"""
316
- if name in self ._keywords or name in self .property_types :
321
+ if ( name in self ._keywords or name in self .property_types ) or not self . validate_setattr :
317
322
return super ().__setattr__ (name , value )
318
323
319
324
raise InvalidResourceException (
0 commit comments