localstack-core 4.4.1.dev60__py3-none-any.whl → 4.4.1.dev65__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. localstack/aws/api/ec2/__init__.py +70 -2
  2. localstack/aws/api/s3/__init__.py +2 -0
  3. localstack/services/cloudformation/engine/v2/change_set_model.py +106 -144
  4. localstack/services/cloudformation/engine/v2/change_set_model_describer.py +9 -7
  5. localstack/services/cloudformation/engine/v2/change_set_model_executor.py +7 -6
  6. localstack/services/cloudformation/engine/v2/change_set_model_preproc.py +223 -114
  7. localstack/services/cloudformation/engine/v2/change_set_model_visitor.py +10 -0
  8. localstack/services/s3/provider.py +3 -2
  9. localstack/services/sns/provider.py +27 -9
  10. localstack/version.py +2 -2
  11. {localstack_core-4.4.1.dev60.dist-info → localstack_core-4.4.1.dev65.dist-info}/METADATA +3 -3
  12. {localstack_core-4.4.1.dev60.dist-info → localstack_core-4.4.1.dev65.dist-info}/RECORD +20 -20
  13. localstack_core-4.4.1.dev65.dist-info/plux.json +1 -0
  14. localstack_core-4.4.1.dev60.dist-info/plux.json +0 -1
  15. {localstack_core-4.4.1.dev60.data → localstack_core-4.4.1.dev65.data}/scripts/localstack +0 -0
  16. {localstack_core-4.4.1.dev60.data → localstack_core-4.4.1.dev65.data}/scripts/localstack-supervisor +0 -0
  17. {localstack_core-4.4.1.dev60.data → localstack_core-4.4.1.dev65.data}/scripts/localstack.bat +0 -0
  18. {localstack_core-4.4.1.dev60.dist-info → localstack_core-4.4.1.dev65.dist-info}/WHEEL +0 -0
  19. {localstack_core-4.4.1.dev60.dist-info → localstack_core-4.4.1.dev65.dist-info}/entry_points.txt +0 -0
  20. {localstack_core-4.4.1.dev60.dist-info → localstack_core-4.4.1.dev65.dist-info}/licenses/LICENSE.txt +0 -0
  21. {localstack_core-4.4.1.dev60.dist-info → localstack_core-4.4.1.dev65.dist-info}/top_level.txt +0 -0
@@ -23,6 +23,9 @@ class NothingType:
23
23
  cls._singleton = super().__new__(cls)
24
24
  return cls._singleton
25
25
 
26
+ def __eq__(self, other):
27
+ return is_nothing(other)
28
+
26
29
  def __str__(self):
27
30
  return repr(self)
28
31
 
@@ -35,11 +38,46 @@ class NothingType:
35
38
  def __iter__(self):
36
39
  return iter(())
37
40
 
41
+ def __contains__(self, item):
42
+ return False
43
+
38
44
 
39
45
  Maybe = Union[T, NothingType]
40
46
  Nothing = NothingType()
41
47
 
42
48
 
49
+ def is_nothing(value: Any) -> bool:
50
+ return isinstance(value, NothingType)
51
+
52
+
53
+ def is_created(before: Maybe[Any], after: Maybe[Any]) -> bool:
54
+ return is_nothing(before) and not is_nothing(after)
55
+
56
+
57
+ def is_removed(before: Maybe[Any], after: Maybe[Any]) -> bool:
58
+ return not is_nothing(before) and is_nothing(after)
59
+
60
+
61
+ def parent_change_type_of(children: list[Maybe[ChangeSetEntity]]):
62
+ change_types = [c.change_type for c in children if not is_nothing(c)]
63
+ if not change_types:
64
+ return ChangeType.UNCHANGED
65
+ first_type = change_types[0]
66
+ if all(ct == first_type for ct in change_types):
67
+ return first_type
68
+ return ChangeType.MODIFIED
69
+
70
+
71
+ def change_type_of(before: Maybe[Any], after: Maybe[Any], children: list[Maybe[ChangeSetEntity]]):
72
+ if is_created(before, after):
73
+ change_type = ChangeType.CREATED
74
+ elif is_removed(before, after):
75
+ change_type = ChangeType.REMOVED
76
+ else:
77
+ change_type = parent_change_type_of(children)
78
+ return change_type
79
+
80
+
43
81
  class Scope(str):
44
82
  _ROOT_SCOPE: Final[str] = str()
45
83
  _SEPARATOR: Final[str] = "/"
@@ -66,14 +104,6 @@ class ChangeType(enum.Enum):
66
104
  def __str__(self):
67
105
  return self.value
68
106
 
69
- def for_child(self, child_change_type: ChangeType) -> ChangeType:
70
- if child_change_type == self:
71
- return self
72
- elif self == ChangeType.UNCHANGED:
73
- return child_change_type
74
- else:
75
- return ChangeType.MODIFIED
76
-
77
107
 
78
108
  class ChangeSetEntity(abc.ABC):
79
109
  scope: Final[Scope]
@@ -122,13 +152,13 @@ class NodeTemplate(ChangeSetNode):
122
152
  def __init__(
123
153
  self,
124
154
  scope: Scope,
125
- change_type: ChangeType,
126
155
  mappings: NodeMappings,
127
156
  parameters: NodeParameters,
128
157
  conditions: NodeConditions,
129
158
  resources: NodeResources,
130
159
  outputs: NodeOutputs,
131
160
  ):
161
+ change_type = parent_change_type_of([resources, outputs])
132
162
  super().__init__(scope=scope, change_type=change_type)
133
163
  self.mappings = mappings
134
164
  self.parameters = parameters
@@ -151,17 +181,17 @@ class NodeParameter(ChangeSetNode):
151
181
  name: Final[str]
152
182
  type_: Final[ChangeSetEntity]
153
183
  dynamic_value: Final[ChangeSetEntity]
154
- default_value: Final[Optional[ChangeSetEntity]]
184
+ default_value: Final[Maybe[ChangeSetEntity]]
155
185
 
156
186
  def __init__(
157
187
  self,
158
188
  scope: Scope,
159
- change_type: ChangeType,
160
189
  name: str,
161
190
  type_: ChangeSetEntity,
162
191
  dynamic_value: ChangeSetEntity,
163
- default_value: Optional[ChangeSetEntity],
192
+ default_value: Maybe[ChangeSetEntity],
164
193
  ):
194
+ change_type = parent_change_type_of([type_, default_value, dynamic_value])
165
195
  super().__init__(scope=scope, change_type=change_type)
166
196
  self.name = name
167
197
  self.type_ = type_
@@ -172,7 +202,8 @@ class NodeParameter(ChangeSetNode):
172
202
  class NodeParameters(ChangeSetNode):
173
203
  parameters: Final[list[NodeParameter]]
174
204
 
175
- def __init__(self, scope: Scope, change_type: ChangeType, parameters: list[NodeParameter]):
205
+ def __init__(self, scope: Scope, parameters: list[NodeParameter]):
206
+ change_type = parent_change_type_of(parameters)
176
207
  super().__init__(scope=scope, change_type=change_type)
177
208
  self.parameters = parameters
178
209
 
@@ -181,8 +212,8 @@ class NodeMapping(ChangeSetNode):
181
212
  name: Final[str]
182
213
  bindings: Final[NodeObject]
183
214
 
184
- def __init__(self, scope: Scope, change_type: ChangeType, name: str, bindings: NodeObject):
185
- super().__init__(scope=scope, change_type=change_type)
215
+ def __init__(self, scope: Scope, name: str, bindings: NodeObject):
216
+ super().__init__(scope=scope, change_type=bindings.change_type)
186
217
  self.name = name
187
218
  self.bindings = bindings
188
219
 
@@ -190,7 +221,8 @@ class NodeMapping(ChangeSetNode):
190
221
  class NodeMappings(ChangeSetNode):
191
222
  mappings: Final[list[NodeMapping]]
192
223
 
193
- def __init__(self, scope: Scope, change_type: ChangeType, mappings: list[NodeMapping]):
224
+ def __init__(self, scope: Scope, mappings: list[NodeMapping]):
225
+ change_type = parent_change_type_of(mappings)
194
226
  super().__init__(scope=scope, change_type=change_type)
195
227
  self.mappings = mappings
196
228
 
@@ -198,18 +230,18 @@ class NodeMappings(ChangeSetNode):
198
230
  class NodeOutput(ChangeSetNode):
199
231
  name: Final[str]
200
232
  value: Final[ChangeSetEntity]
201
- export: Final[Optional[ChangeSetEntity]]
202
- condition_reference: Final[Optional[TerminalValue]]
233
+ export: Final[Maybe[ChangeSetEntity]]
234
+ condition_reference: Final[Maybe[TerminalValue]]
203
235
 
204
236
  def __init__(
205
237
  self,
206
238
  scope: Scope,
207
- change_type: ChangeType,
208
239
  name: str,
209
240
  value: ChangeSetEntity,
210
- export: Optional[ChangeSetEntity],
211
- conditional_reference: Optional[TerminalValue],
241
+ export: Maybe[ChangeSetEntity],
242
+ conditional_reference: Maybe[TerminalValue],
212
243
  ):
244
+ change_type = parent_change_type_of([value, export, conditional_reference])
213
245
  super().__init__(scope=scope, change_type=change_type)
214
246
  self.name = name
215
247
  self.value = value
@@ -220,7 +252,8 @@ class NodeOutput(ChangeSetNode):
220
252
  class NodeOutputs(ChangeSetNode):
221
253
  outputs: Final[list[NodeOutput]]
222
254
 
223
- def __init__(self, scope: Scope, change_type: ChangeType, outputs: list[NodeOutput]):
255
+ def __init__(self, scope: Scope, outputs: list[NodeOutput]):
256
+ change_type = parent_change_type_of(outputs)
224
257
  super().__init__(scope=scope, change_type=change_type)
225
258
  self.outputs = outputs
226
259
 
@@ -229,8 +262,8 @@ class NodeCondition(ChangeSetNode):
229
262
  name: Final[str]
230
263
  body: Final[ChangeSetEntity]
231
264
 
232
- def __init__(self, scope: Scope, change_type: ChangeType, name: str, body: ChangeSetEntity):
233
- super().__init__(scope=scope, change_type=change_type)
265
+ def __init__(self, scope: Scope, name: str, body: ChangeSetEntity):
266
+ super().__init__(scope=scope, change_type=body.change_type)
234
267
  self.name = name
235
268
  self.body = body
236
269
 
@@ -238,7 +271,8 @@ class NodeCondition(ChangeSetNode):
238
271
  class NodeConditions(ChangeSetNode):
239
272
  conditions: Final[list[NodeCondition]]
240
273
 
241
- def __init__(self, scope: Scope, change_type: ChangeType, conditions: list[NodeCondition]):
274
+ def __init__(self, scope: Scope, conditions: list[NodeCondition]):
275
+ change_type = parent_change_type_of(conditions)
242
276
  super().__init__(scope=scope, change_type=change_type)
243
277
  self.conditions = conditions
244
278
 
@@ -246,7 +280,8 @@ class NodeConditions(ChangeSetNode):
246
280
  class NodeResources(ChangeSetNode):
247
281
  resources: Final[list[NodeResource]]
248
282
 
249
- def __init__(self, scope: Scope, change_type: ChangeType, resources: list[NodeResource]):
283
+ def __init__(self, scope: Scope, resources: list[NodeResource]):
284
+ change_type = parent_change_type_of(resources)
250
285
  super().__init__(scope=scope, change_type=change_type)
251
286
  self.resources = resources
252
287
 
@@ -254,9 +289,9 @@ class NodeResources(ChangeSetNode):
254
289
  class NodeResource(ChangeSetNode):
255
290
  name: Final[str]
256
291
  type_: Final[ChangeSetTerminal]
257
- condition_reference: Final[Optional[TerminalValue]]
258
292
  properties: Final[NodeProperties]
259
- depends_on: Final[Optional[NodeDependsOn]]
293
+ condition_reference: Final[Maybe[TerminalValue]]
294
+ depends_on: Final[Maybe[NodeDependsOn]]
260
295
 
261
296
  def __init__(
262
297
  self,
@@ -265,8 +300,8 @@ class NodeResource(ChangeSetNode):
265
300
  name: str,
266
301
  type_: ChangeSetTerminal,
267
302
  properties: NodeProperties,
268
- condition_reference: Optional[TerminalValue],
269
- depends_on: Optional[NodeDependsOn],
303
+ condition_reference: Maybe[TerminalValue],
304
+ depends_on: Maybe[NodeDependsOn],
270
305
  ):
271
306
  super().__init__(scope=scope, change_type=change_type)
272
307
  self.name = name
@@ -279,7 +314,8 @@ class NodeResource(ChangeSetNode):
279
314
  class NodeProperties(ChangeSetNode):
280
315
  properties: Final[list[NodeProperty]]
281
316
 
282
- def __init__(self, scope: Scope, change_type: ChangeType, properties: list[NodeProperty]):
317
+ def __init__(self, scope: Scope, properties: list[NodeProperty]):
318
+ change_type = parent_change_type_of(properties)
283
319
  super().__init__(scope=scope, change_type=change_type)
284
320
  self.properties = properties
285
321
 
@@ -287,8 +323,8 @@ class NodeProperties(ChangeSetNode):
287
323
  class NodeDependsOn(ChangeSetNode):
288
324
  depends_on: Final[NodeArray]
289
325
 
290
- def __init__(self, scope: Scope, change_type: ChangeType, depends_on: NodeArray):
291
- super().__init__(scope=scope, change_type=change_type)
326
+ def __init__(self, scope: Scope, depends_on: NodeArray):
327
+ super().__init__(scope=scope, change_type=depends_on.change_type)
292
328
  self.depends_on = depends_on
293
329
 
294
330
 
@@ -296,8 +332,8 @@ class NodeProperty(ChangeSetNode):
296
332
  name: Final[str]
297
333
  value: Final[ChangeSetEntity]
298
334
 
299
- def __init__(self, scope: Scope, change_type: ChangeType, name: str, value: ChangeSetEntity):
300
- super().__init__(scope=scope, change_type=change_type)
335
+ def __init__(self, scope: Scope, name: str, value: ChangeSetEntity):
336
+ super().__init__(scope=scope, change_type=value.change_type)
301
337
  self.name = name
302
338
  self.value = value
303
339
 
@@ -386,6 +422,8 @@ FnGetAttKey: Final[str] = "Fn::GetAtt"
386
422
  FnEqualsKey: Final[str] = "Fn::Equals"
387
423
  FnFindInMapKey: Final[str] = "Fn::FindInMap"
388
424
  FnSubKey: Final[str] = "Fn::Sub"
425
+ FnTransform: Final[str] = "Fn::Transform"
426
+ FnSelect: Final[str] = "Fn::Select"
389
427
  INTRINSIC_FUNCTIONS: Final[set[str]] = {
390
428
  RefKey,
391
429
  FnIfKey,
@@ -395,6 +433,8 @@ INTRINSIC_FUNCTIONS: Final[set[str]] = {
395
433
  FnGetAttKey,
396
434
  FnFindInMapKey,
397
435
  FnSubKey,
436
+ FnTransform,
437
+ FnSelect,
398
438
  }
399
439
 
400
440
 
@@ -440,9 +480,9 @@ class ChangeSetModel:
440
480
  terminal_value = self._visited_scopes.get(scope)
441
481
  if isinstance(terminal_value, TerminalValue):
442
482
  return terminal_value
443
- if self._is_created(before=before_value, after=after_value):
483
+ if is_created(before=before_value, after=after_value):
444
484
  terminal_value = TerminalValueCreated(scope=scope, value=after_value)
445
- elif self._is_removed(before=before_value, after=after_value):
485
+ elif is_removed(before=before_value, after=after_value):
446
486
  terminal_value = TerminalValueRemoved(scope=scope, value=before_value)
447
487
  elif before_value == after_value:
448
488
  terminal_value = TerminalValueUnchanged(scope=scope, value=before_value)
@@ -466,9 +506,9 @@ class ChangeSetModel:
466
506
  arguments = self._visit_value(
467
507
  scope=scope, before_value=before_arguments, after_value=after_arguments
468
508
  )
469
- if self._is_created(before=before_arguments, after=after_arguments):
509
+ if is_created(before=before_arguments, after=after_arguments):
470
510
  change_type = ChangeType.CREATED
471
- elif self._is_removed(before=before_arguments, after=after_arguments):
511
+ elif is_removed(before=before_arguments, after=after_arguments):
472
512
  change_type = ChangeType.REMOVED
473
513
  else:
474
514
  function_name = intrinsic_function.replace("::", "_")
@@ -586,8 +626,7 @@ class ChangeSetModel:
586
626
  )
587
627
  if not isinstance(node_condition, NodeCondition):
588
628
  raise RuntimeError()
589
- change_types = [node_condition.change_type, *arguments.array[1:]]
590
- change_type = self._change_type_for_parent_of(change_types=change_types)
629
+ change_type = parent_change_type_of([node_condition, *arguments[1:]])
591
630
  return change_type
592
631
 
593
632
  def _visit_array(
@@ -602,12 +641,7 @@ class ChangeSetModel:
602
641
  scope=value_scope, before_value=before_value, after_value=after_value
603
642
  )
604
643
  array.append(value)
605
- if self._is_created(before=before_array, after=after_array):
606
- change_type = ChangeType.CREATED
607
- elif self._is_removed(before=before_array, after=after_array):
608
- change_type = ChangeType.REMOVED
609
- else:
610
- change_type = self._change_type_for_parent_of([value.change_type for value in array])
644
+ change_type = change_type_of(before_array, after_array, array)
611
645
  return NodeArray(scope=scope, change_type=change_type, array=array)
612
646
 
613
647
  def _visit_object(
@@ -616,12 +650,6 @@ class ChangeSetModel:
616
650
  node_object = self._visited_scopes.get(scope)
617
651
  if isinstance(node_object, NodeObject):
618
652
  return node_object
619
- if self._is_created(before=before_object, after=after_object):
620
- change_type = ChangeType.CREATED
621
- elif self._is_removed(before=before_object, after=after_object):
622
- change_type = ChangeType.REMOVED
623
- else:
624
- change_type = ChangeType.UNCHANGED
625
653
  binding_names = self._safe_keys_of(before_object, after_object)
626
654
  bindings: dict[str, ChangeSetEntity] = dict()
627
655
  for binding_name in binding_names:
@@ -632,7 +660,7 @@ class ChangeSetModel:
632
660
  scope=binding_scope, before_value=before_value, after_value=after_value
633
661
  )
634
662
  bindings[binding_name] = value
635
- change_type = change_type.for_child(value.change_type)
663
+ change_type = change_type_of(before_object, after_object, list(bindings.values()))
636
664
  node_object = NodeObject(scope=scope, change_type=change_type, bindings=bindings)
637
665
  self._visited_scopes[scope] = node_object
638
666
  return node_object
@@ -660,9 +688,9 @@ class ChangeSetModel:
660
688
  unset = object()
661
689
  if before_type_name == after_type_name:
662
690
  dominant_value = before_value
663
- elif self._is_created(before=before_value, after=after_value):
691
+ elif is_created(before=before_value, after=after_value):
664
692
  dominant_value = after_value
665
- elif self._is_removed(before=before_value, after=after_value):
693
+ elif is_removed(before=before_value, after=after_value):
666
694
  dominant_value = before_value
667
695
  else:
668
696
  dominant_value = unset
@@ -713,9 +741,7 @@ class ChangeSetModel:
713
741
  value = self._visit_value(
714
742
  scope=scope, before_value=before_property, after_value=after_property
715
743
  )
716
- node_property = NodeProperty(
717
- scope=scope, change_type=value.change_type, name=property_name, value=value
718
- )
744
+ node_property = NodeProperty(scope=scope, name=property_name, value=value)
719
745
  self._visited_scopes[scope] = node_property
720
746
  return node_property
721
747
 
@@ -725,10 +751,8 @@ class ChangeSetModel:
725
751
  node_properties = self._visited_scopes.get(scope)
726
752
  if isinstance(node_properties, NodeProperties):
727
753
  return node_properties
728
- # TODO: double check we are sure not to have this be a NodeObject
729
754
  property_names: list[str] = self._safe_keys_of(before_properties, after_properties)
730
755
  properties: list[NodeProperty] = list()
731
- change_type = ChangeType.UNCHANGED
732
756
  for property_name in property_names:
733
757
  property_scope, (before_property, after_property) = self._safe_access_in(
734
758
  scope, property_name, before_properties, after_properties
@@ -740,10 +764,7 @@ class ChangeSetModel:
740
764
  after_property=after_property,
741
765
  )
742
766
  properties.append(property_)
743
- change_type = change_type.for_child(property_.change_type)
744
- node_properties = NodeProperties(
745
- scope=scope, change_type=change_type, properties=properties
746
- )
767
+ node_properties = NodeProperties(scope=scope, properties=properties)
747
768
  self._visited_scopes[scope] = node_properties
748
769
  return node_properties
749
770
 
@@ -765,13 +786,6 @@ class ChangeSetModel:
765
786
  if isinstance(node_resource, NodeResource):
766
787
  return node_resource
767
788
 
768
- if self._is_created(before=before_resource, after=after_resource):
769
- change_type = ChangeType.CREATED
770
- elif self._is_removed(before=before_resource, after=after_resource):
771
- change_type = ChangeType.REMOVED
772
- else:
773
- change_type = ChangeType.UNCHANGED
774
-
775
789
  scope_type, (before_type, after_type) = self._safe_access_in(
776
790
  scope, TypeKey, before_resource, after_resource
777
791
  )
@@ -779,7 +793,7 @@ class ChangeSetModel:
779
793
  scope=scope_type, before_type=before_type, after_type=after_type
780
794
  )
781
795
 
782
- condition_reference = None
796
+ condition_reference = Nothing
783
797
  scope_condition, (before_condition, after_condition) = self._safe_access_in(
784
798
  scope, ConditionKey, before_resource, after_resource
785
799
  )
@@ -788,7 +802,7 @@ class ChangeSetModel:
788
802
  scope_condition, before_condition, after_condition
789
803
  )
790
804
 
791
- depends_on = None
805
+ depends_on = Nothing
792
806
  scope_depends_on, (before_depends_on, after_depends_on) = self._safe_access_in(
793
807
  scope, DependsOnKey, before_resource, after_resource
794
808
  )
@@ -805,10 +819,10 @@ class ChangeSetModel:
805
819
  before_properties=before_properties,
806
820
  after_properties=after_properties,
807
821
  )
808
- if properties.properties:
809
- # Properties were defined in the before or after template, thus must play a role
810
- # in affecting the change type of this resource.
811
- change_type = change_type.for_child(properties.change_type)
822
+
823
+ change_type = change_type_of(
824
+ before_resource, after_resource, [properties, condition_reference, depends_on]
825
+ )
812
826
  node_resource = NodeResource(
813
827
  scope=scope,
814
828
  change_type=change_type,
@@ -825,7 +839,6 @@ class ChangeSetModel:
825
839
  self, scope: Scope, before_resources: Maybe[dict], after_resources: Maybe[dict]
826
840
  ) -> NodeResources:
827
841
  # TODO: investigate type changes behavior.
828
- change_type = ChangeType.UNCHANGED
829
842
  resources: list[NodeResource] = list()
830
843
  resource_names = self._safe_keys_of(before_resources, after_resources)
831
844
  for resource_name in resource_names:
@@ -839,8 +852,7 @@ class ChangeSetModel:
839
852
  after_resource=after_resource,
840
853
  )
841
854
  resources.append(resource)
842
- change_type = change_type.for_child(resource.change_type)
843
- return NodeResources(scope=scope, change_type=change_type, resources=resources)
855
+ return NodeResources(scope=scope, resources=resources)
844
856
 
845
857
  def _visit_mapping(
846
858
  self, scope: Scope, name: str, before_mapping: Maybe[dict], after_mapping: Maybe[dict]
@@ -848,14 +860,11 @@ class ChangeSetModel:
848
860
  bindings = self._visit_object(
849
861
  scope=scope, before_object=before_mapping, after_object=after_mapping
850
862
  )
851
- return NodeMapping(
852
- scope=scope, change_type=bindings.change_type, name=name, bindings=bindings
853
- )
863
+ return NodeMapping(scope=scope, name=name, bindings=bindings)
854
864
 
855
865
  def _visit_mappings(
856
866
  self, scope: Scope, before_mappings: Maybe[dict], after_mappings: Maybe[dict]
857
867
  ) -> NodeMappings:
858
- change_type = ChangeType.UNCHANGED
859
868
  mappings: list[NodeMapping] = list()
860
869
  mapping_names = self._safe_keys_of(before_mappings, after_mappings)
861
870
  for mapping_name in mapping_names:
@@ -869,8 +878,7 @@ class ChangeSetModel:
869
878
  after_mapping=after_mapping,
870
879
  )
871
880
  mappings.append(mapping)
872
- change_type = change_type.for_child(mapping.change_type)
873
- return NodeMappings(scope=scope, change_type=change_type, mappings=mappings)
881
+ return NodeMappings(scope=scope, mappings=mappings)
874
882
 
875
883
  def _visit_dynamic_parameter(self, parameter_name: str) -> ChangeSetEntity:
876
884
  scope = Scope("Dynamic").open_scope("Parameters")
@@ -905,13 +913,8 @@ class ChangeSetModel:
905
913
 
906
914
  dynamic_value = self._visit_dynamic_parameter(parameter_name=parameter_name)
907
915
 
908
- change_type = self._change_type_for_parent_of(
909
- change_types=[type_.change_type, default_value.change_type, dynamic_value.change_type]
910
- )
911
-
912
916
  node_parameter = NodeParameter(
913
917
  scope=scope,
914
- change_type=change_type,
915
918
  name=parameter_name,
916
919
  type_=type_,
917
920
  default_value=default_value,
@@ -928,7 +931,6 @@ class ChangeSetModel:
928
931
  return node_parameters
929
932
  parameter_names: list[str] = self._safe_keys_of(before_parameters, after_parameters)
930
933
  parameters: list[NodeParameter] = list()
931
- change_type = ChangeType.UNCHANGED
932
934
  for parameter_name in parameter_names:
933
935
  parameter_scope, (before_parameter, after_parameter) = self._safe_access_in(
934
936
  scope, parameter_name, before_parameters, after_parameters
@@ -940,10 +942,7 @@ class ChangeSetModel:
940
942
  after_parameter=after_parameter,
941
943
  )
942
944
  parameters.append(parameter)
943
- change_type = change_type.for_child(parameter.change_type)
944
- node_parameters = NodeParameters(
945
- scope=scope, change_type=change_type, parameters=parameters
946
- )
945
+ node_parameters = NodeParameters(scope=scope, parameters=parameters)
947
946
  self._visited_scopes[scope] = node_parameters
948
947
  return node_parameters
949
948
 
@@ -974,9 +973,7 @@ class ChangeSetModel:
974
973
  node_array = self._visit_array(
975
974
  scope=scope, before_array=before_depends_on, after_array=after_depends_on
976
975
  )
977
- node_depends_on = NodeDependsOn(
978
- scope=scope, change_type=node_array.change_type, depends_on=node_array
979
- )
976
+ node_depends_on = NodeDependsOn(scope=scope, depends_on=node_array)
980
977
  return node_depends_on
981
978
 
982
979
  def _visit_condition(
@@ -992,9 +989,7 @@ class ChangeSetModel:
992
989
  body = self._visit_value(
993
990
  scope=scope, before_value=before_condition, after_value=after_condition
994
991
  )
995
- node_condition = NodeCondition(
996
- scope=scope, change_type=body.change_type, name=condition_name, body=body
997
- )
992
+ node_condition = NodeCondition(scope=scope, name=condition_name, body=body)
998
993
  self._visited_scopes[scope] = node_condition
999
994
  return node_condition
1000
995
 
@@ -1006,7 +1001,6 @@ class ChangeSetModel:
1006
1001
  return node_conditions
1007
1002
  condition_names: list[str] = self._safe_keys_of(before_conditions, after_conditions)
1008
1003
  conditions: list[NodeCondition] = list()
1009
- change_type = ChangeType.UNCHANGED
1010
1004
  for condition_name in condition_names:
1011
1005
  condition_scope, (before_condition, after_condition) = self._safe_access_in(
1012
1006
  scope, condition_name, before_conditions, after_conditions
@@ -1018,33 +1012,27 @@ class ChangeSetModel:
1018
1012
  after_condition=after_condition,
1019
1013
  )
1020
1014
  conditions.append(condition)
1021
- change_type = change_type.for_child(child_change_type=condition.change_type)
1022
- node_conditions = NodeConditions(
1023
- scope=scope, change_type=change_type, conditions=conditions
1024
- )
1015
+ node_conditions = NodeConditions(scope=scope, conditions=conditions)
1025
1016
  self._visited_scopes[scope] = node_conditions
1026
1017
  return node_conditions
1027
1018
 
1028
1019
  def _visit_output(
1029
1020
  self, scope: Scope, name: str, before_output: Maybe[dict], after_output: Maybe[dict]
1030
1021
  ) -> NodeOutput:
1031
- change_type = ChangeType.UNCHANGED
1032
1022
  scope_value, (before_value, after_value) = self._safe_access_in(
1033
1023
  scope, ValueKey, before_output, after_output
1034
1024
  )
1035
1025
  value = self._visit_value(scope_value, before_value, after_value)
1036
- change_type = change_type.for_child(value.change_type)
1037
1026
 
1038
- export: Optional[ChangeSetEntity] = None
1027
+ export: Maybe[ChangeSetEntity] = Nothing
1039
1028
  scope_export, (before_export, after_export) = self._safe_access_in(
1040
1029
  scope, ExportKey, before_output, after_output
1041
1030
  )
1042
1031
  if before_export or after_export:
1043
1032
  export = self._visit_value(scope_export, before_export, after_export)
1044
- change_type = change_type.for_child(export.change_type)
1045
1033
 
1046
1034
  # TODO: condition references should be resolved for the condition's change_type?
1047
- condition_reference: Optional[TerminalValue] = None
1035
+ condition_reference: Maybe[TerminalValue] = Nothing
1048
1036
  scope_condition, (before_condition, after_condition) = self._safe_access_in(
1049
1037
  scope, ConditionKey, before_output, after_output
1050
1038
  )
@@ -1052,11 +1040,9 @@ class ChangeSetModel:
1052
1040
  condition_reference = self._visit_terminal_value(
1053
1041
  scope_condition, before_condition, after_condition
1054
1042
  )
1055
- change_type = change_type.for_child(condition_reference.change_type)
1056
1043
 
1057
1044
  return NodeOutput(
1058
1045
  scope=scope,
1059
- change_type=change_type,
1060
1046
  name=name,
1061
1047
  value=value,
1062
1048
  export=export,
@@ -1066,7 +1052,6 @@ class ChangeSetModel:
1066
1052
  def _visit_outputs(
1067
1053
  self, scope: Scope, before_outputs: Maybe[dict], after_outputs: Maybe[dict]
1068
1054
  ) -> NodeOutputs:
1069
- change_type = ChangeType.UNCHANGED
1070
1055
  outputs: list[NodeOutput] = list()
1071
1056
  output_names: list[str] = self._safe_keys_of(before_outputs, after_outputs)
1072
1057
  for output_name in output_names:
@@ -1080,8 +1065,7 @@ class ChangeSetModel:
1080
1065
  after_output=after_output,
1081
1066
  )
1082
1067
  outputs.append(output)
1083
- change_type = change_type.for_child(output.change_type)
1084
- return NodeOutputs(scope=scope, change_type=change_type, outputs=outputs)
1068
+ return NodeOutputs(scope=scope, outputs=outputs)
1085
1069
 
1086
1070
  def _model(self, before_template: Maybe[dict], after_template: Maybe[dict]) -> NodeTemplate:
1087
1071
  root_scope = Scope()
@@ -1131,7 +1115,6 @@ class ChangeSetModel:
1131
1115
  # TODO: compute the change_type of the template properly.
1132
1116
  return NodeTemplate(
1133
1117
  scope=root_scope,
1134
- change_type=resources.change_type,
1135
1118
  mappings=mappings,
1136
1119
  parameters=parameters,
1137
1120
  conditions=conditions,
@@ -1139,7 +1122,7 @@ class ChangeSetModel:
1139
1122
  outputs=outputs,
1140
1123
  )
1141
1124
 
1142
- def _retrieve_condition_if_exists(self, condition_name: str) -> Optional[NodeCondition]:
1125
+ def _retrieve_condition_if_exists(self, condition_name: str) -> Maybe[NodeCondition]:
1143
1126
  conditions_scope, (before_conditions, after_conditions) = self._safe_access_in(
1144
1127
  Scope(), ConditionsKey, self._before_template, self._after_template
1145
1128
  )
@@ -1156,14 +1139,12 @@ class ChangeSetModel:
1156
1139
  after_condition=after_condition,
1157
1140
  )
1158
1141
  return node_condition
1159
- return None
1142
+ return Nothing
1160
1143
 
1161
- def _retrieve_parameter_if_exists(self, parameter_name: str) -> Optional[NodeParameter]:
1144
+ def _retrieve_parameter_if_exists(self, parameter_name: str) -> Maybe[NodeParameter]:
1162
1145
  parameters_scope, (before_parameters, after_parameters) = self._safe_access_in(
1163
1146
  Scope(), ParametersKey, self._before_template, self._after_template
1164
1147
  )
1165
- before_parameters = before_parameters or dict()
1166
- after_parameters = after_parameters or dict()
1167
1148
  if parameter_name in before_parameters or parameter_name in after_parameters:
1168
1149
  parameter_scope, (before_parameter, after_parameter) = self._safe_access_in(
1169
1150
  parameters_scope, parameter_name, before_parameters, after_parameters
@@ -1175,15 +1156,13 @@ class ChangeSetModel:
1175
1156
  after_parameter=after_parameter,
1176
1157
  )
1177
1158
  return node_parameter
1178
- return None
1159
+ return Nothing
1179
1160
 
1180
1161
  def _retrieve_mapping(self, mapping_name) -> NodeMapping:
1181
1162
  # TODO: add caching mechanism, and raise appropriate error if missing.
1182
1163
  scope_mappings, (before_mappings, after_mappings) = self._safe_access_in(
1183
1164
  Scope(), MappingsKey, self._before_template, self._after_template
1184
1165
  )
1185
- before_mappings = before_mappings or dict()
1186
- after_mappings = after_mappings or dict()
1187
1166
  if mapping_name in before_mappings or mapping_name in after_mappings:
1188
1167
  scope_mapping, (before_mapping, after_mapping) = self._safe_access_in(
1189
1168
  scope_mappings, mapping_name, before_mappings, after_mappings
@@ -1240,15 +1219,6 @@ class ChangeSetModel:
1240
1219
  keys = sorted(key_set)
1241
1220
  return keys
1242
1221
 
1243
- @staticmethod
1244
- def _change_type_for_parent_of(change_types: list[ChangeType]) -> ChangeType:
1245
- parent_change_type = ChangeType.UNCHANGED
1246
- for child_change_type in change_types:
1247
- parent_change_type = parent_change_type.for_child(child_change_type)
1248
- if parent_change_type == ChangeType.MODIFIED:
1249
- break
1250
- return parent_change_type
1251
-
1252
1222
  @staticmethod
1253
1223
  def _name_if_intrinsic_function(value: Maybe[Any]) -> Optional[str]:
1254
1224
  if isinstance(value, dict):
@@ -1277,11 +1247,3 @@ class ChangeSetModel:
1277
1247
  @staticmethod
1278
1248
  def _is_array(value: Any) -> bool:
1279
1249
  return isinstance(value, list)
1280
-
1281
- @staticmethod
1282
- def _is_created(before: Maybe[Any], after: Maybe[Any]) -> bool:
1283
- return isinstance(before, NothingType) and not isinstance(after, NothingType)
1284
-
1285
- @staticmethod
1286
- def _is_removed(before: Maybe[Any], after: Maybe[Any]) -> bool:
1287
- return not isinstance(before, NothingType) and isinstance(after, NothingType)