localstack-core 4.4.1.dev59__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.
- localstack/aws/api/ec2/__init__.py +70 -2
- localstack/aws/api/s3/__init__.py +2 -0
- localstack/services/cloudformation/engine/v2/change_set_model.py +107 -146
- localstack/services/cloudformation/engine/v2/change_set_model_describer.py +41 -22
- localstack/services/cloudformation/engine/v2/change_set_model_executor.py +51 -23
- localstack/services/cloudformation/engine/v2/change_set_model_preproc.py +244 -123
- localstack/services/cloudformation/engine/v2/change_set_model_visitor.py +16 -1
- localstack/services/s3/provider.py +3 -2
- localstack/services/sns/provider.py +27 -9
- localstack/testing/pytest/cloudformation/fixtures.py +13 -1
- localstack/version.py +2 -2
- {localstack_core-4.4.1.dev59.dist-info → localstack_core-4.4.1.dev65.dist-info}/METADATA +3 -3
- {localstack_core-4.4.1.dev59.dist-info → localstack_core-4.4.1.dev65.dist-info}/RECORD +21 -21
- localstack_core-4.4.1.dev65.dist-info/plux.json +1 -0
- localstack_core-4.4.1.dev59.dist-info/plux.json +0 -1
- {localstack_core-4.4.1.dev59.data → localstack_core-4.4.1.dev65.data}/scripts/localstack +0 -0
- {localstack_core-4.4.1.dev59.data → localstack_core-4.4.1.dev65.data}/scripts/localstack-supervisor +0 -0
- {localstack_core-4.4.1.dev59.data → localstack_core-4.4.1.dev65.data}/scripts/localstack.bat +0 -0
- {localstack_core-4.4.1.dev59.dist-info → localstack_core-4.4.1.dev65.dist-info}/WHEEL +0 -0
- {localstack_core-4.4.1.dev59.dist-info → localstack_core-4.4.1.dev65.dist-info}/entry_points.txt +0 -0
- {localstack_core-4.4.1.dev59.dist-info → localstack_core-4.4.1.dev65.dist-info}/licenses/LICENSE.txt +0 -0
- {localstack_core-4.4.1.dev59.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[
|
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:
|
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,
|
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,
|
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,
|
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[
|
202
|
-
condition_reference: Final[
|
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:
|
211
|
-
conditional_reference:
|
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,
|
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,
|
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,
|
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,
|
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
|
-
|
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:
|
269
|
-
depends_on:
|
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,
|
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,
|
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,
|
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
|
483
|
+
if is_created(before=before_value, after=after_value):
|
444
484
|
terminal_value = TerminalValueCreated(scope=scope, value=after_value)
|
445
|
-
elif
|
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
|
509
|
+
if is_created(before=before_arguments, after=after_arguments):
|
470
510
|
change_type = ChangeType.CREATED
|
471
|
-
elif
|
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("::", "_")
|
@@ -523,7 +563,6 @@ class ChangeSetModel:
|
|
523
563
|
def _resolve_intrinsic_function_ref(self, arguments: ChangeSetEntity) -> ChangeType:
|
524
564
|
if arguments.change_type != ChangeType.UNCHANGED:
|
525
565
|
return arguments.change_type
|
526
|
-
# TODO: add support for nested functions, here we assume the argument is a logicalID.
|
527
566
|
if not isinstance(arguments, TerminalValue):
|
528
567
|
return arguments.change_type
|
529
568
|
|
@@ -587,8 +626,7 @@ class ChangeSetModel:
|
|
587
626
|
)
|
588
627
|
if not isinstance(node_condition, NodeCondition):
|
589
628
|
raise RuntimeError()
|
590
|
-
|
591
|
-
change_type = self._change_type_for_parent_of(change_types=change_types)
|
629
|
+
change_type = parent_change_type_of([node_condition, *arguments[1:]])
|
592
630
|
return change_type
|
593
631
|
|
594
632
|
def _visit_array(
|
@@ -603,12 +641,7 @@ class ChangeSetModel:
|
|
603
641
|
scope=value_scope, before_value=before_value, after_value=after_value
|
604
642
|
)
|
605
643
|
array.append(value)
|
606
|
-
|
607
|
-
change_type = ChangeType.CREATED
|
608
|
-
elif self._is_removed(before=before_array, after=after_array):
|
609
|
-
change_type = ChangeType.REMOVED
|
610
|
-
else:
|
611
|
-
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)
|
612
645
|
return NodeArray(scope=scope, change_type=change_type, array=array)
|
613
646
|
|
614
647
|
def _visit_object(
|
@@ -617,12 +650,6 @@ class ChangeSetModel:
|
|
617
650
|
node_object = self._visited_scopes.get(scope)
|
618
651
|
if isinstance(node_object, NodeObject):
|
619
652
|
return node_object
|
620
|
-
if self._is_created(before=before_object, after=after_object):
|
621
|
-
change_type = ChangeType.CREATED
|
622
|
-
elif self._is_removed(before=before_object, after=after_object):
|
623
|
-
change_type = ChangeType.REMOVED
|
624
|
-
else:
|
625
|
-
change_type = ChangeType.UNCHANGED
|
626
653
|
binding_names = self._safe_keys_of(before_object, after_object)
|
627
654
|
bindings: dict[str, ChangeSetEntity] = dict()
|
628
655
|
for binding_name in binding_names:
|
@@ -633,7 +660,7 @@ class ChangeSetModel:
|
|
633
660
|
scope=binding_scope, before_value=before_value, after_value=after_value
|
634
661
|
)
|
635
662
|
bindings[binding_name] = value
|
636
|
-
|
663
|
+
change_type = change_type_of(before_object, after_object, list(bindings.values()))
|
637
664
|
node_object = NodeObject(scope=scope, change_type=change_type, bindings=bindings)
|
638
665
|
self._visited_scopes[scope] = node_object
|
639
666
|
return node_object
|
@@ -661,9 +688,9 @@ class ChangeSetModel:
|
|
661
688
|
unset = object()
|
662
689
|
if before_type_name == after_type_name:
|
663
690
|
dominant_value = before_value
|
664
|
-
elif
|
691
|
+
elif is_created(before=before_value, after=after_value):
|
665
692
|
dominant_value = after_value
|
666
|
-
elif
|
693
|
+
elif is_removed(before=before_value, after=after_value):
|
667
694
|
dominant_value = before_value
|
668
695
|
else:
|
669
696
|
dominant_value = unset
|
@@ -714,9 +741,7 @@ class ChangeSetModel:
|
|
714
741
|
value = self._visit_value(
|
715
742
|
scope=scope, before_value=before_property, after_value=after_property
|
716
743
|
)
|
717
|
-
node_property = NodeProperty(
|
718
|
-
scope=scope, change_type=value.change_type, name=property_name, value=value
|
719
|
-
)
|
744
|
+
node_property = NodeProperty(scope=scope, name=property_name, value=value)
|
720
745
|
self._visited_scopes[scope] = node_property
|
721
746
|
return node_property
|
722
747
|
|
@@ -726,10 +751,8 @@ class ChangeSetModel:
|
|
726
751
|
node_properties = self._visited_scopes.get(scope)
|
727
752
|
if isinstance(node_properties, NodeProperties):
|
728
753
|
return node_properties
|
729
|
-
# TODO: double check we are sure not to have this be a NodeObject
|
730
754
|
property_names: list[str] = self._safe_keys_of(before_properties, after_properties)
|
731
755
|
properties: list[NodeProperty] = list()
|
732
|
-
change_type = ChangeType.UNCHANGED
|
733
756
|
for property_name in property_names:
|
734
757
|
property_scope, (before_property, after_property) = self._safe_access_in(
|
735
758
|
scope, property_name, before_properties, after_properties
|
@@ -741,10 +764,7 @@ class ChangeSetModel:
|
|
741
764
|
after_property=after_property,
|
742
765
|
)
|
743
766
|
properties.append(property_)
|
744
|
-
|
745
|
-
node_properties = NodeProperties(
|
746
|
-
scope=scope, change_type=change_type, properties=properties
|
747
|
-
)
|
767
|
+
node_properties = NodeProperties(scope=scope, properties=properties)
|
748
768
|
self._visited_scopes[scope] = node_properties
|
749
769
|
return node_properties
|
750
770
|
|
@@ -766,13 +786,6 @@ class ChangeSetModel:
|
|
766
786
|
if isinstance(node_resource, NodeResource):
|
767
787
|
return node_resource
|
768
788
|
|
769
|
-
if self._is_created(before=before_resource, after=after_resource):
|
770
|
-
change_type = ChangeType.CREATED
|
771
|
-
elif self._is_removed(before=before_resource, after=after_resource):
|
772
|
-
change_type = ChangeType.REMOVED
|
773
|
-
else:
|
774
|
-
change_type = ChangeType.UNCHANGED
|
775
|
-
|
776
789
|
scope_type, (before_type, after_type) = self._safe_access_in(
|
777
790
|
scope, TypeKey, before_resource, after_resource
|
778
791
|
)
|
@@ -780,7 +793,7 @@ class ChangeSetModel:
|
|
780
793
|
scope=scope_type, before_type=before_type, after_type=after_type
|
781
794
|
)
|
782
795
|
|
783
|
-
condition_reference =
|
796
|
+
condition_reference = Nothing
|
784
797
|
scope_condition, (before_condition, after_condition) = self._safe_access_in(
|
785
798
|
scope, ConditionKey, before_resource, after_resource
|
786
799
|
)
|
@@ -789,7 +802,7 @@ class ChangeSetModel:
|
|
789
802
|
scope_condition, before_condition, after_condition
|
790
803
|
)
|
791
804
|
|
792
|
-
depends_on =
|
805
|
+
depends_on = Nothing
|
793
806
|
scope_depends_on, (before_depends_on, after_depends_on) = self._safe_access_in(
|
794
807
|
scope, DependsOnKey, before_resource, after_resource
|
795
808
|
)
|
@@ -806,10 +819,10 @@ class ChangeSetModel:
|
|
806
819
|
before_properties=before_properties,
|
807
820
|
after_properties=after_properties,
|
808
821
|
)
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
822
|
+
|
823
|
+
change_type = change_type_of(
|
824
|
+
before_resource, after_resource, [properties, condition_reference, depends_on]
|
825
|
+
)
|
813
826
|
node_resource = NodeResource(
|
814
827
|
scope=scope,
|
815
828
|
change_type=change_type,
|
@@ -826,7 +839,6 @@ class ChangeSetModel:
|
|
826
839
|
self, scope: Scope, before_resources: Maybe[dict], after_resources: Maybe[dict]
|
827
840
|
) -> NodeResources:
|
828
841
|
# TODO: investigate type changes behavior.
|
829
|
-
change_type = ChangeType.UNCHANGED
|
830
842
|
resources: list[NodeResource] = list()
|
831
843
|
resource_names = self._safe_keys_of(before_resources, after_resources)
|
832
844
|
for resource_name in resource_names:
|
@@ -840,8 +852,7 @@ class ChangeSetModel:
|
|
840
852
|
after_resource=after_resource,
|
841
853
|
)
|
842
854
|
resources.append(resource)
|
843
|
-
|
844
|
-
return NodeResources(scope=scope, change_type=change_type, resources=resources)
|
855
|
+
return NodeResources(scope=scope, resources=resources)
|
845
856
|
|
846
857
|
def _visit_mapping(
|
847
858
|
self, scope: Scope, name: str, before_mapping: Maybe[dict], after_mapping: Maybe[dict]
|
@@ -849,14 +860,11 @@ class ChangeSetModel:
|
|
849
860
|
bindings = self._visit_object(
|
850
861
|
scope=scope, before_object=before_mapping, after_object=after_mapping
|
851
862
|
)
|
852
|
-
return NodeMapping(
|
853
|
-
scope=scope, change_type=bindings.change_type, name=name, bindings=bindings
|
854
|
-
)
|
863
|
+
return NodeMapping(scope=scope, name=name, bindings=bindings)
|
855
864
|
|
856
865
|
def _visit_mappings(
|
857
866
|
self, scope: Scope, before_mappings: Maybe[dict], after_mappings: Maybe[dict]
|
858
867
|
) -> NodeMappings:
|
859
|
-
change_type = ChangeType.UNCHANGED
|
860
868
|
mappings: list[NodeMapping] = list()
|
861
869
|
mapping_names = self._safe_keys_of(before_mappings, after_mappings)
|
862
870
|
for mapping_name in mapping_names:
|
@@ -870,8 +878,7 @@ class ChangeSetModel:
|
|
870
878
|
after_mapping=after_mapping,
|
871
879
|
)
|
872
880
|
mappings.append(mapping)
|
873
|
-
|
874
|
-
return NodeMappings(scope=scope, change_type=change_type, mappings=mappings)
|
881
|
+
return NodeMappings(scope=scope, mappings=mappings)
|
875
882
|
|
876
883
|
def _visit_dynamic_parameter(self, parameter_name: str) -> ChangeSetEntity:
|
877
884
|
scope = Scope("Dynamic").open_scope("Parameters")
|
@@ -906,13 +913,8 @@ class ChangeSetModel:
|
|
906
913
|
|
907
914
|
dynamic_value = self._visit_dynamic_parameter(parameter_name=parameter_name)
|
908
915
|
|
909
|
-
change_type = self._change_type_for_parent_of(
|
910
|
-
change_types=[type_.change_type, default_value.change_type, dynamic_value.change_type]
|
911
|
-
)
|
912
|
-
|
913
916
|
node_parameter = NodeParameter(
|
914
917
|
scope=scope,
|
915
|
-
change_type=change_type,
|
916
918
|
name=parameter_name,
|
917
919
|
type_=type_,
|
918
920
|
default_value=default_value,
|
@@ -929,7 +931,6 @@ class ChangeSetModel:
|
|
929
931
|
return node_parameters
|
930
932
|
parameter_names: list[str] = self._safe_keys_of(before_parameters, after_parameters)
|
931
933
|
parameters: list[NodeParameter] = list()
|
932
|
-
change_type = ChangeType.UNCHANGED
|
933
934
|
for parameter_name in parameter_names:
|
934
935
|
parameter_scope, (before_parameter, after_parameter) = self._safe_access_in(
|
935
936
|
scope, parameter_name, before_parameters, after_parameters
|
@@ -941,10 +942,7 @@ class ChangeSetModel:
|
|
941
942
|
after_parameter=after_parameter,
|
942
943
|
)
|
943
944
|
parameters.append(parameter)
|
944
|
-
|
945
|
-
node_parameters = NodeParameters(
|
946
|
-
scope=scope, change_type=change_type, parameters=parameters
|
947
|
-
)
|
945
|
+
node_parameters = NodeParameters(scope=scope, parameters=parameters)
|
948
946
|
self._visited_scopes[scope] = node_parameters
|
949
947
|
return node_parameters
|
950
948
|
|
@@ -975,9 +973,7 @@ class ChangeSetModel:
|
|
975
973
|
node_array = self._visit_array(
|
976
974
|
scope=scope, before_array=before_depends_on, after_array=after_depends_on
|
977
975
|
)
|
978
|
-
node_depends_on = NodeDependsOn(
|
979
|
-
scope=scope, change_type=node_array.change_type, depends_on=node_array
|
980
|
-
)
|
976
|
+
node_depends_on = NodeDependsOn(scope=scope, depends_on=node_array)
|
981
977
|
return node_depends_on
|
982
978
|
|
983
979
|
def _visit_condition(
|
@@ -993,9 +989,7 @@ class ChangeSetModel:
|
|
993
989
|
body = self._visit_value(
|
994
990
|
scope=scope, before_value=before_condition, after_value=after_condition
|
995
991
|
)
|
996
|
-
node_condition = NodeCondition(
|
997
|
-
scope=scope, change_type=body.change_type, name=condition_name, body=body
|
998
|
-
)
|
992
|
+
node_condition = NodeCondition(scope=scope, name=condition_name, body=body)
|
999
993
|
self._visited_scopes[scope] = node_condition
|
1000
994
|
return node_condition
|
1001
995
|
|
@@ -1007,7 +1001,6 @@ class ChangeSetModel:
|
|
1007
1001
|
return node_conditions
|
1008
1002
|
condition_names: list[str] = self._safe_keys_of(before_conditions, after_conditions)
|
1009
1003
|
conditions: list[NodeCondition] = list()
|
1010
|
-
change_type = ChangeType.UNCHANGED
|
1011
1004
|
for condition_name in condition_names:
|
1012
1005
|
condition_scope, (before_condition, after_condition) = self._safe_access_in(
|
1013
1006
|
scope, condition_name, before_conditions, after_conditions
|
@@ -1019,33 +1012,27 @@ class ChangeSetModel:
|
|
1019
1012
|
after_condition=after_condition,
|
1020
1013
|
)
|
1021
1014
|
conditions.append(condition)
|
1022
|
-
|
1023
|
-
node_conditions = NodeConditions(
|
1024
|
-
scope=scope, change_type=change_type, conditions=conditions
|
1025
|
-
)
|
1015
|
+
node_conditions = NodeConditions(scope=scope, conditions=conditions)
|
1026
1016
|
self._visited_scopes[scope] = node_conditions
|
1027
1017
|
return node_conditions
|
1028
1018
|
|
1029
1019
|
def _visit_output(
|
1030
1020
|
self, scope: Scope, name: str, before_output: Maybe[dict], after_output: Maybe[dict]
|
1031
1021
|
) -> NodeOutput:
|
1032
|
-
change_type = ChangeType.UNCHANGED
|
1033
1022
|
scope_value, (before_value, after_value) = self._safe_access_in(
|
1034
1023
|
scope, ValueKey, before_output, after_output
|
1035
1024
|
)
|
1036
1025
|
value = self._visit_value(scope_value, before_value, after_value)
|
1037
|
-
change_type = change_type.for_child(value.change_type)
|
1038
1026
|
|
1039
|
-
export:
|
1027
|
+
export: Maybe[ChangeSetEntity] = Nothing
|
1040
1028
|
scope_export, (before_export, after_export) = self._safe_access_in(
|
1041
1029
|
scope, ExportKey, before_output, after_output
|
1042
1030
|
)
|
1043
1031
|
if before_export or after_export:
|
1044
1032
|
export = self._visit_value(scope_export, before_export, after_export)
|
1045
|
-
change_type = change_type.for_child(export.change_type)
|
1046
1033
|
|
1047
1034
|
# TODO: condition references should be resolved for the condition's change_type?
|
1048
|
-
condition_reference:
|
1035
|
+
condition_reference: Maybe[TerminalValue] = Nothing
|
1049
1036
|
scope_condition, (before_condition, after_condition) = self._safe_access_in(
|
1050
1037
|
scope, ConditionKey, before_output, after_output
|
1051
1038
|
)
|
@@ -1053,11 +1040,9 @@ class ChangeSetModel:
|
|
1053
1040
|
condition_reference = self._visit_terminal_value(
|
1054
1041
|
scope_condition, before_condition, after_condition
|
1055
1042
|
)
|
1056
|
-
change_type = change_type.for_child(condition_reference.change_type)
|
1057
1043
|
|
1058
1044
|
return NodeOutput(
|
1059
1045
|
scope=scope,
|
1060
|
-
change_type=change_type,
|
1061
1046
|
name=name,
|
1062
1047
|
value=value,
|
1063
1048
|
export=export,
|
@@ -1067,7 +1052,6 @@ class ChangeSetModel:
|
|
1067
1052
|
def _visit_outputs(
|
1068
1053
|
self, scope: Scope, before_outputs: Maybe[dict], after_outputs: Maybe[dict]
|
1069
1054
|
) -> NodeOutputs:
|
1070
|
-
change_type = ChangeType.UNCHANGED
|
1071
1055
|
outputs: list[NodeOutput] = list()
|
1072
1056
|
output_names: list[str] = self._safe_keys_of(before_outputs, after_outputs)
|
1073
1057
|
for output_name in output_names:
|
@@ -1081,8 +1065,7 @@ class ChangeSetModel:
|
|
1081
1065
|
after_output=after_output,
|
1082
1066
|
)
|
1083
1067
|
outputs.append(output)
|
1084
|
-
|
1085
|
-
return NodeOutputs(scope=scope, change_type=change_type, outputs=outputs)
|
1068
|
+
return NodeOutputs(scope=scope, outputs=outputs)
|
1086
1069
|
|
1087
1070
|
def _model(self, before_template: Maybe[dict], after_template: Maybe[dict]) -> NodeTemplate:
|
1088
1071
|
root_scope = Scope()
|
@@ -1132,7 +1115,6 @@ class ChangeSetModel:
|
|
1132
1115
|
# TODO: compute the change_type of the template properly.
|
1133
1116
|
return NodeTemplate(
|
1134
1117
|
scope=root_scope,
|
1135
|
-
change_type=resources.change_type,
|
1136
1118
|
mappings=mappings,
|
1137
1119
|
parameters=parameters,
|
1138
1120
|
conditions=conditions,
|
@@ -1140,7 +1122,7 @@ class ChangeSetModel:
|
|
1140
1122
|
outputs=outputs,
|
1141
1123
|
)
|
1142
1124
|
|
1143
|
-
def _retrieve_condition_if_exists(self, condition_name: str) ->
|
1125
|
+
def _retrieve_condition_if_exists(self, condition_name: str) -> Maybe[NodeCondition]:
|
1144
1126
|
conditions_scope, (before_conditions, after_conditions) = self._safe_access_in(
|
1145
1127
|
Scope(), ConditionsKey, self._before_template, self._after_template
|
1146
1128
|
)
|
@@ -1157,34 +1139,30 @@ class ChangeSetModel:
|
|
1157
1139
|
after_condition=after_condition,
|
1158
1140
|
)
|
1159
1141
|
return node_condition
|
1160
|
-
return
|
1142
|
+
return Nothing
|
1161
1143
|
|
1162
|
-
def _retrieve_parameter_if_exists(self, parameter_name: str) ->
|
1144
|
+
def _retrieve_parameter_if_exists(self, parameter_name: str) -> Maybe[NodeParameter]:
|
1163
1145
|
parameters_scope, (before_parameters, after_parameters) = self._safe_access_in(
|
1164
1146
|
Scope(), ParametersKey, self._before_template, self._after_template
|
1165
1147
|
)
|
1166
|
-
before_parameters = before_parameters or dict()
|
1167
|
-
after_parameters = after_parameters or dict()
|
1168
1148
|
if parameter_name in before_parameters or parameter_name in after_parameters:
|
1169
1149
|
parameter_scope, (before_parameter, after_parameter) = self._safe_access_in(
|
1170
1150
|
parameters_scope, parameter_name, before_parameters, after_parameters
|
1171
1151
|
)
|
1172
1152
|
node_parameter = self._visit_parameter(
|
1173
|
-
|
1153
|
+
parameter_scope,
|
1174
1154
|
parameter_name,
|
1175
1155
|
before_parameter=before_parameter,
|
1176
1156
|
after_parameter=after_parameter,
|
1177
1157
|
)
|
1178
1158
|
return node_parameter
|
1179
|
-
return
|
1159
|
+
return Nothing
|
1180
1160
|
|
1181
1161
|
def _retrieve_mapping(self, mapping_name) -> NodeMapping:
|
1182
1162
|
# TODO: add caching mechanism, and raise appropriate error if missing.
|
1183
1163
|
scope_mappings, (before_mappings, after_mappings) = self._safe_access_in(
|
1184
1164
|
Scope(), MappingsKey, self._before_template, self._after_template
|
1185
1165
|
)
|
1186
|
-
before_mappings = before_mappings or dict()
|
1187
|
-
after_mappings = after_mappings or dict()
|
1188
1166
|
if mapping_name in before_mappings or mapping_name in after_mappings:
|
1189
1167
|
scope_mapping, (before_mapping, after_mapping) = self._safe_access_in(
|
1190
1168
|
scope_mappings, mapping_name, before_mappings, after_mappings
|
@@ -1241,15 +1219,6 @@ class ChangeSetModel:
|
|
1241
1219
|
keys = sorted(key_set)
|
1242
1220
|
return keys
|
1243
1221
|
|
1244
|
-
@staticmethod
|
1245
|
-
def _change_type_for_parent_of(change_types: list[ChangeType]) -> ChangeType:
|
1246
|
-
parent_change_type = ChangeType.UNCHANGED
|
1247
|
-
for child_change_type in change_types:
|
1248
|
-
parent_change_type = parent_change_type.for_child(child_change_type)
|
1249
|
-
if parent_change_type == ChangeType.MODIFIED:
|
1250
|
-
break
|
1251
|
-
return parent_change_type
|
1252
|
-
|
1253
1222
|
@staticmethod
|
1254
1223
|
def _name_if_intrinsic_function(value: Maybe[Any]) -> Optional[str]:
|
1255
1224
|
if isinstance(value, dict):
|
@@ -1278,11 +1247,3 @@ class ChangeSetModel:
|
|
1278
1247
|
@staticmethod
|
1279
1248
|
def _is_array(value: Any) -> bool:
|
1280
1249
|
return isinstance(value, list)
|
1281
|
-
|
1282
|
-
@staticmethod
|
1283
|
-
def _is_created(before: Maybe[Any], after: Maybe[Any]) -> bool:
|
1284
|
-
return isinstance(before, NothingType) and not isinstance(after, NothingType)
|
1285
|
-
|
1286
|
-
@staticmethod
|
1287
|
-
def _is_removed(before: Maybe[Any], after: Maybe[Any]) -> bool:
|
1288
|
-
return not isinstance(before, NothingType) and isinstance(after, NothingType)
|