cdk-factory 0.8.1__py3-none-any.whl → 0.8.3__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.

Potentially problematic release.


This version of cdk-factory might be problematic. Click here for more details.

@@ -142,28 +142,39 @@ class EnhancedSsmParameterMixin:
142
142
  Returns:
143
143
  Created SSM parameter
144
144
  """
145
- # Handle different value types
146
- if isinstance(value, list):
147
- string_value = ",".join(str(v) for v in value)
148
- cdk_param_type = ssm.ParameterType.STRING_LIST
149
- elif param_type == "SecureString":
150
- string_value = str(value)
151
- cdk_param_type = ssm.ParameterType.SECURE_STRING
152
- else:
153
- string_value = str(value)
154
- cdk_param_type = ssm.ParameterType.STRING
155
-
156
145
  # Generate a unique construct ID from the path
157
146
  construct_id = f"ssm-param-{path.replace('/', '-').replace('_', '-')}"
158
147
 
159
- return ssm.StringParameter(
160
- self.scope,
161
- construct_id,
162
- parameter_name=path,
163
- string_value=string_value,
164
- description=description,
165
- type=cdk_param_type
166
- )
148
+ # Handle different value types - use appropriate CDK constructs
149
+ if isinstance(value, list):
150
+ # For list values, use StringListParameter
151
+ return ssm.StringListParameter(
152
+ self.scope,
153
+ construct_id,
154
+ parameter_name=path,
155
+ string_list_value=value,
156
+ description=description
157
+ )
158
+ elif param_type == "SecureString":
159
+ # For secure strings, use L1 CfnParameter with Type=SecureString
160
+ return ssm.CfnParameter(
161
+ self.scope,
162
+ construct_id,
163
+ name=path,
164
+ value=str(value),
165
+ type="SecureString",
166
+ description=description
167
+ )
168
+ else:
169
+ # For regular strings, use StringParameter (no type parameter needed in CDK v2)
170
+ return ssm.StringParameter(
171
+ self.scope,
172
+ construct_id,
173
+ parameter_name=path,
174
+ string_value=str(value),
175
+ description=description
176
+ # Note: 'type' parameter removed - deprecated in CDK v2
177
+ )
167
178
 
168
179
  def _import_enhanced_ssm_parameter(self, path: str, attribute: str) -> Optional[str]:
169
180
  """
@@ -436,12 +436,16 @@ class ApiGatewayStack(IStack, EnhancedSsmParameterMixin):
436
436
  return None
437
437
 
438
438
  def _setup_single_lambda_route(self, api_gateway, api_id, route, authorizer):
439
- """
440
- Setup a single Lambda route with integration and CORS.
441
- LEGACY PATTERN: Creates a new Lambda function inline.
442
- Prefer _setup_existing_lambda_route for new implementations.
443
- """
444
- suffix = route["path"].strip("/").replace("/", "-") or "health"
439
+ """Setup a single Lambda route with integration and CORS"""
440
+ # Use the 'name' field if provided, otherwise include method in suffix for uniqueness
441
+ if "name" in route and route["name"]:
442
+ suffix = route["name"] # Use the unique name provided in config
443
+ else:
444
+ # Include method to ensure uniqueness when same path has multiple methods
445
+ method = route.get("method", "GET").upper()
446
+ path_suffix = route["path"].strip("/").replace("/", "-") or "health"
447
+ suffix = f"{method.lower()}-{path_suffix}"
448
+
445
449
  src = route.get("src")
446
450
  handler = route.get("handler")
447
451
 
@@ -14,16 +14,30 @@ class JsonLoadingUtility:
14
14
  """
15
15
  JSON Loading Utility
16
16
  This class is used to load a JSON file. We have a special syntax that allows
17
- chaining JSON files together using __inherits__
17
+ chaining JSON files together using __imports__ or __inherits__ (legacy).
18
+
19
+ The __imports__ keyword allows you to:
20
+ - Import from external JSON files: "__imports__": "./base-config.json"
21
+ - Import from nested sections: "__imports__": "workload.defaults"
22
+ - Import from directories: "__imports__": "./configs/"
23
+ - Import multiple sources: "__imports__": ["base.json", "overrides.json"]
18
24
 
19
25
  Examples:
20
- TODO - show some examples
26
+ # Single file import
27
+ {"__imports__": "./base-config.json", "name": "override"}
28
+
29
+ # Multiple imports (merged in order)
30
+ {"__imports__": ["base.json", "env-specific.json"]}
31
+
32
+ # Nested section reference
33
+ {"__imports__": "workload.defaults.lambda"}
21
34
  """
22
35
 
23
36
  def __init__(self, path) -> None:
24
37
  self.path = path
25
38
  self.base_path = os.path.dirname(path)
26
- self.nested_key = "__inherits__"
39
+ # Support both __imports__ (preferred) and __inherits__ (legacy)
40
+ self.import_keys = ["__imports__", "__inherits__"]
27
41
 
28
42
  def load(self):
29
43
  """Load and parse the JSON object for nested resources."""
@@ -60,36 +74,74 @@ class JsonLoadingUtility:
60
74
  ):
61
75
  """Resolve references in a configuration section."""
62
76
  if isinstance(section, dict):
63
- if self.nested_key in section:
64
- nested_path = str(section.pop(self.nested_key))
65
- # print(f"Resolving parent path: {nested_path}")
66
- if nested_path.endswith(".json"):
67
- nested_root_path = os.path.join(self.base_path, nested_path)
68
- nested_section = self.__load_json_file(nested_root_path)
69
- elif os.path.isdir(os.path.join(self.base_path, nested_path)):
70
- nested_section = []
71
- dir_path = os.path.join(self.base_path, nested_path)
72
- for filename in os.listdir(dir_path):
73
- if filename.endswith(".json"):
74
- file_path = os.path.join(dir_path, filename)
75
- # print(f"Loading file: {file_path}")
76
- file_section = self.__load_json_file(file_path)
77
- nested_section.append(file_section)
78
-
79
- # print("done with nested sections")
80
- else:
81
- nested_section = self.get_nested_config(root_config, nested_path)
82
-
83
- nested_section_resolved = self.resolve_references(
84
- nested_section, root_config
85
- )
86
- if len(section) > 0 and isinstance(nested_section_resolved, dict):
87
- nested_section_resolved.update(section)
88
- elif len(section) > 0 and isinstance(nested_section_resolved, list):
77
+ # Check for import keys (try __imports__ first, fall back to __inherits__)
78
+ import_key = None
79
+ for key in self.import_keys:
80
+ if key in section:
81
+ import_key = key
82
+ break
83
+
84
+ if import_key:
85
+ nested_paths = section.pop(import_key)
86
+
87
+ # Support both single path (string) and multiple paths (list)
88
+ if isinstance(nested_paths, str):
89
+ nested_paths = [nested_paths]
90
+ elif not isinstance(nested_paths, list):
91
+ raise ValueError(
92
+ f"{import_key} must be a string or list of paths, got {type(nested_paths)}. "
93
+ f"Example: '{import_key}': './base.json' or '{import_key}': ['base.json', 'overrides.json']"
94
+ )
95
+
96
+ # Process each path and merge results
97
+ merged_section = None
98
+
99
+ for nested_path in nested_paths:
100
+ nested_path = str(nested_path)
101
+ # print(f"Resolving parent path: {nested_path}")
102
+
103
+ if nested_path.endswith(".json"):
104
+ nested_root_path = os.path.join(self.base_path, nested_path)
105
+ nested_section = self.__load_json_file(nested_root_path)
106
+ elif os.path.isdir(os.path.join(self.base_path, nested_path)):
107
+ nested_section = []
108
+ dir_path = os.path.join(self.base_path, nested_path)
109
+ for filename in os.listdir(dir_path):
110
+ if filename.endswith(".json"):
111
+ file_path = os.path.join(dir_path, filename)
112
+ # print(f"Loading file: {file_path}")
113
+ file_section = self.__load_json_file(file_path)
114
+ nested_section.append(file_section)
115
+ # print("done with nested sections")
116
+ else:
117
+ nested_section = self.get_nested_config(root_config, nested_path)
118
+
119
+ nested_section_resolved = self.resolve_references(
120
+ nested_section, root_config
121
+ )
122
+
123
+ # Merge resolved sections
124
+ if merged_section is None:
125
+ merged_section = nested_section_resolved
126
+ else:
127
+ # Merge logic based on type
128
+ if isinstance(merged_section, dict) and isinstance(nested_section_resolved, dict):
129
+ self.merge_sections(merged_section, nested_section_resolved)
130
+ elif isinstance(merged_section, list) and isinstance(nested_section_resolved, list):
131
+ merged_section.extend(nested_section_resolved)
132
+ else:
133
+ raise RuntimeError(
134
+ f"Cannot merge incompatible types: {type(merged_section)} and {type(nested_section_resolved)}"
135
+ )
136
+
137
+ # Apply any additional properties from the section
138
+ if len(section) > 0 and isinstance(merged_section, dict):
139
+ merged_section.update(section)
140
+ elif len(section) > 0 and isinstance(merged_section, list):
89
141
  raise RuntimeError("we need to resolve this section")
90
- # nested_section_resolved.append(section)
142
+ # merged_section.append(section)
91
143
 
92
- section = nested_section_resolved
144
+ section = merged_section
93
145
 
94
146
  if isinstance(section, dict):
95
147
  for key, value in section.items():
cdk_factory/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.8.1"
1
+ __version__ = "0.8.3"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cdk_factory
3
- Version: 0.8.1
3
+ Version: 0.8.3
4
4
  Summary: CDK Factory. A QuickStarter and best practices setup for CDK projects
5
5
  Author-email: Eric Wilson <eric.wilson@geekcafe.com>
6
6
  License: MIT License
@@ -1,7 +1,7 @@
1
1
  cdk_factory/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  cdk_factory/app.py,sha256=xv863N7O6HPKznB68_t7O4la9JacrkG87t9TjoDUk7s,2827
3
3
  cdk_factory/cdk.json,sha256=SKZKhJ2PBpFH78j-F8S3VDYW-lf76--Q2I3ON-ZIQfw,3106
4
- cdk_factory/version.py,sha256=Ocl79hbbH8_jdr5dGC90VR1cAvZc05Rc0tkZttUnMjo,22
4
+ cdk_factory/version.py,sha256=otnwfmvJLUamPajTPUaIekiO9mA-2HPi-_h_E0N-uOQ,22
5
5
  cdk_factory/builds/README.md,sha256=9BBWd7bXpyKdMU_g2UljhQwrC9i5O_Tvkb6oPvndoZk,90
6
6
  cdk_factory/commands/command_loader.py,sha256=QbLquuP_AdxtlxlDy-2IWCQ6D-7qa58aphnDPtp_uTs,3744
7
7
  cdk_factory/configurations/base_config.py,sha256=JKjhNsy0RCUZy1s8n5D_aXXI-upR9izaLtCTfKYiV9k,9624
@@ -57,7 +57,7 @@ cdk_factory/constructs/s3_buckets/s3_bucket_construct.py,sha256=5DK5aVUAveJYBjmP
57
57
  cdk_factory/constructs/s3_buckets/s3_bucket_replication_destination_construct.py,sha256=H-EJ2Q71LI5FPQ9thMkXDGRuwJdFc_2OzGIrWA98lxg,2517
58
58
  cdk_factory/constructs/s3_buckets/s3_bucket_replication_source_construct.py,sha256=ZLKbRcMK1q73VruxCH62XbymebKt-lKV5Kul9OjkZiA,3763
59
59
  cdk_factory/constructs/sqs/policies/sqs_policies.py,sha256=4p0G8G-fqNKSr68I55fvqH-DkhIeXyGaFBKkICIJ-qM,1277
60
- cdk_factory/interfaces/enhanced_ssm_parameter_mixin.py,sha256=k-jfwRJhIs6sxifmh7rFaX92tpHMdxiZ8mgPP4NNu5E,13041
60
+ cdk_factory/interfaces/enhanced_ssm_parameter_mixin.py,sha256=GYFaUo_vzmuox8dK0U-cI9d-OBhToXlTkrWeveGZr3k,13522
61
61
  cdk_factory/interfaces/istack.py,sha256=bhTBs-o9FgKwvJMSuwxjUV6D3nUlvZHVzfm27jP9x9Y,987
62
62
  cdk_factory/interfaces/live_ssm_resolver.py,sha256=3FIr9a02SXqZmbFs3RT0WxczWEQR_CF7QSt7kWbDrVE,8163
63
63
  cdk_factory/interfaces/ssm_parameter_mixin.py,sha256=uA2j8HmAOpuEA9ynRj51s0WjUHMVLsbLQN-QS9NKyHA,12089
@@ -73,7 +73,7 @@ cdk_factory/stack/stack_module_registry.py,sha256=J14-A75VZESzRQa8p-Fepdap7Z8T7m
73
73
  cdk_factory/stack/stack_modules.py,sha256=kgEK-j0smZPozVwTCfM1g1V17EyTBT0TXAQZq4vZz0o,784
74
74
  cdk_factory/stack_library/__init__.py,sha256=5Y9TpIe8ZK1688G60PGcuP-hM0RvYEY_3Hl2qJCJJrw,581
75
75
  cdk_factory/stack_library/stack_base.py,sha256=tTleSFmlf26DuKVF_ytftf8P7IVWb5iex8cYfYupfvQ,4940
76
- cdk_factory/stack_library/api_gateway/api_gateway_stack.py,sha256=5rWHwLc6kI99YHUA1xqLtzcEhDmMB4p-xB9gLQ6o8JE,37916
76
+ cdk_factory/stack_library/api_gateway/api_gateway_stack.py,sha256=AdC_TTAgdOIagahEuMZcA208E6osjO1lK80I6E1k5cc,38212
77
77
  cdk_factory/stack_library/auto_scaling/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
78
  cdk_factory/stack_library/auto_scaling/auto_scaling_stack.py,sha256=UsFqUb_3XPJAlmZ6F75nXna3elOggD1KuFmmdmhi0Lg,19070
79
79
  cdk_factory/stack_library/aws_lambdas/lambda_stack.py,sha256=SFbBPvvCopbyiuYtq-O5sQkFCf94Wzua6aDUXiFDSB4,26161
@@ -107,12 +107,12 @@ cdk_factory/utilities/docker_utilities.py,sha256=9r8C-lXYpymqEfi3gTeWCQzHldvfjtt
107
107
  cdk_factory/utilities/environment_services.py,sha256=cd2T0efJtFPMLa1Fm7MPL-sqUlhKXCB7_XHsR8sfymE,9696
108
108
  cdk_factory/utilities/file_operations.py,sha256=HCZevKlmnHNB2wkIEPtdm-g2nJSKT3B9uipLk8Kx_Yk,8946
109
109
  cdk_factory/utilities/git_utilities.py,sha256=7Xac8PaThc7Lmk5jtDBHaJOj-fWRT017cgZmgXkVizM,3155
110
- cdk_factory/utilities/json_loading_utility.py,sha256=zdvqO2Bw5OpImJymfQRgqr6wfpZSCVtL20sYCYPAvMg,7617
110
+ cdk_factory/utilities/json_loading_utility.py,sha256=YRgzA1I-B_HwZm1eWJTeQ1JLkebCL4C1gpHOqo6GkCA,10341
111
111
  cdk_factory/utilities/lambda_function_utilities.py,sha256=j3tBdv_gC2MdEwBINDwAqYey5vgn7YiQtJ0XZybTsCQ,15197
112
112
  cdk_factory/utilities/os_execute.py,sha256=5Op0LY_8Y-pUm04y1k8MTpNrmQvcLmQHPQITEP7EuSU,1019
113
113
  cdk_factory/utils/api_gateway_utilities.py,sha256=If7Xu5s_UxmuV-kL3JkXxPLBdSVUKoLtohm0IUFoiV8,4378
114
114
  cdk_factory/workload/workload_factory.py,sha256=yBUDGIuB8-5p_mGcVFxsD2ZoZIziak3yh3LL3JvS0M4,5903
115
- cdk_factory-0.8.1.dist-info/METADATA,sha256=QzIZhYxS_Mu7hgXTGdT4yN4K0gtJP6Z1Cn1C7onszAg,2450
116
- cdk_factory-0.8.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
117
- cdk_factory-0.8.1.dist-info/licenses/LICENSE,sha256=NOtdOeLwg2il_XBJdXUPFPX8JlV4dqTdDGAd2-khxT8,1066
118
- cdk_factory-0.8.1.dist-info/RECORD,,
115
+ cdk_factory-0.8.3.dist-info/METADATA,sha256=yE-OmEZQq02UmCyeqJXEL3H3nkMU3qVba2GuHqDWfqo,2450
116
+ cdk_factory-0.8.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
117
+ cdk_factory-0.8.3.dist-info/licenses/LICENSE,sha256=NOtdOeLwg2il_XBJdXUPFPX8JlV4dqTdDGAd2-khxT8,1066
118
+ cdk_factory-0.8.3.dist-info/RECORD,,