kodexa 7.4.414330611518__tar.gz → 7.4.414560697286__tar.gz

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 (51) hide show
  1. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/PKG-INFO +1 -1
  2. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/model/objects.py +14 -0
  3. kodexa-7.4.414560697286/kodexa/platform/manifest.py +303 -0
  4. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/pyproject.toml +1 -1
  5. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/LICENSE +0 -0
  6. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/README.md +0 -0
  7. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/__init__.py +0 -0
  8. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/assistant/__init__.py +0 -0
  9. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/assistant/assistant.py +0 -0
  10. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/connectors/__init__.py +0 -0
  11. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/connectors/connectors.py +0 -0
  12. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/dataclasses/__init__.py +0 -0
  13. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/dataclasses/templates/llm_data_class.j2 +0 -0
  14. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/model/__init__.py +0 -0
  15. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/model/base.py +0 -0
  16. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/model/entities/__init__.py +0 -0
  17. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/model/entities/check_response.py +0 -0
  18. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/model/entities/product.py +0 -0
  19. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/model/entities/product_group.py +0 -0
  20. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/model/entities/product_subscription.py +0 -0
  21. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/model/model.py +0 -0
  22. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/model/persistence.py +0 -0
  23. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/model/utils.py +0 -0
  24. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/pipeline/__init__.py +0 -0
  25. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/pipeline/pipeline.py +0 -0
  26. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/platform/__init__.py +0 -0
  27. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/platform/client.py +0 -0
  28. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/platform/interaction.py +0 -0
  29. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/platform/kodexa.py +0 -0
  30. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/selectors/__init__.py +0 -0
  31. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/selectors/ast.py +0 -0
  32. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/selectors/core.py +0 -0
  33. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/selectors/lexrules.py +0 -0
  34. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/selectors/lextab.py +0 -0
  35. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/selectors/lextab.pyi +0 -0
  36. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/selectors/parserules.py +0 -0
  37. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/selectors/parserules.pyi +0 -0
  38. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/selectors/parsetab.py +0 -0
  39. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/selectors/parsetab.pyi +0 -0
  40. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/spatial/__init__.py +0 -0
  41. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/spatial/azure_models.py +0 -0
  42. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/spatial/bbox_common.py +0 -0
  43. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/spatial/table_form_common.py +0 -0
  44. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/steps/__init__.py +0 -0
  45. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/steps/common.py +0 -0
  46. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/testing/__init__.py +0 -0
  47. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/testing/test_components.py +0 -0
  48. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/testing/test_utils.py +0 -0
  49. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/training/__init__.py +0 -0
  50. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/training/train_utils.py +0 -0
  51. {kodexa-7.4.414330611518 → kodexa-7.4.414560697286}/kodexa/utils/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kodexa
3
- Version: 7.4.414330611518
3
+ Version: 7.4.414560697286
4
4
  Summary: Python SDK for the Kodexa Platform
5
5
  Author: Austin Redenbaugh
6
6
  Author-email: austin@kodexa.com
@@ -6285,6 +6285,20 @@ class ScheduledEvent(BaseModel):
6285
6285
  next_event: Optional[StandardDateTime] = Field(None, alias="nextEvent")
6286
6286
 
6287
6287
 
6288
+ class OrchestrationEvent(BaseModel):
6289
+ """
6290
+
6291
+ """
6292
+ model_config = ConfigDict(
6293
+ populate_by_name=True,
6294
+ use_enum_values=True,
6295
+ arbitrary_types_allowed=True,
6296
+ protected_namespaces=("model_config",),
6297
+ )
6298
+ type: Optional[str] = None
6299
+ execution_event: Optional[ExecutionEvent] = Field(None, alias="executionEvent")
6300
+
6301
+
6288
6302
  ThrowableProblem.model_rebuild()
6289
6303
  Option.model_rebuild()
6290
6304
  Taxon.model_rebuild()
@@ -0,0 +1,303 @@
1
+ import yaml
2
+ import os
3
+ import glob
4
+ import logging
5
+ import json
6
+ from kodexa import KodexaClient
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ class ManifestManager:
12
+ """
13
+ A class to manage the manifests for deploying and monitoring
14
+ Kodexa use-cases
15
+ """
16
+
17
+ def __init__(self, kodexa_client: KodexaClient):
18
+ self.kodexa_client = kodexa_client
19
+
20
+ @staticmethod
21
+ def read_manifest(manifest_path: str) -> list:
22
+ """
23
+ Read and parse a YAML manifest file and extract resource paths.
24
+
25
+ Args:
26
+ manifest_path (str): Path to the YAML manifest file.
27
+
28
+ Returns:
29
+ list: List of resource paths extracted from the manifest file.
30
+ Returns an empty list if 'resource-paths' key is not present
31
+ or the file doesn't exist.
32
+ """
33
+ if not os.path.exists(manifest_path):
34
+ logger.warning(f"Manifest file not found: {manifest_path}")
35
+ return []
36
+ try:
37
+ with open(manifest_path, 'r') as file:
38
+ manifest = yaml.safe_load(file)
39
+ # Support 'resource-paths' as the primary key
40
+ return manifest.get('resource-paths', [])
41
+ except Exception as e:
42
+ logger.error(
43
+ f"Failed to read or parse manifest {manifest_path}: {e}",
44
+ exc_info=True
45
+ )
46
+ return []
47
+
48
+ def deploy_from_manifest(self, manifest_path: str,
49
+ org_slug: str | None = None):
50
+ """
51
+ Deploys all resources listed in a manifest file.
52
+
53
+ Args:
54
+ manifest_path (str): The path to the manifest file.
55
+ org_slug (str | None): The organization slug to deploy to. If None,
56
+ uses the default org from the client.
57
+ """
58
+ target_org_slug = org_slug or self.kodexa_client.get_org_slug()
59
+ if not target_org_slug:
60
+ msg = "Organization slug must be provided or set in the client."
61
+ raise ValueError(msg)
62
+
63
+ logger.info(
64
+ f"Starting deployment from manifest {manifest_path} "
65
+ f"to organization {target_org_slug}"
66
+ )
67
+ resource_paths = self.read_manifest(manifest_path)
68
+ abs_manifest_path = os.path.abspath(manifest_path)
69
+ manifest_dir = os.path.dirname(abs_manifest_path)
70
+ original_cwd = os.getcwd()
71
+ deployed_count = 0
72
+
73
+ try:
74
+ # Change to manifest directory to resolve relative paths
75
+ os.chdir(manifest_dir)
76
+
77
+ for resource_pattern in resource_paths:
78
+ # Use glob to find matching files
79
+ resource_files = glob.glob(resource_pattern, recursive=True)
80
+
81
+ if not resource_files:
82
+ logger.warning(
83
+ f"No files found matching pattern '{resource_pattern}' "
84
+ f"relative to {manifest_dir}"
85
+ )
86
+ continue
87
+
88
+ for rel_path in resource_files:
89
+ # Resolve absolute path based on current directory
90
+ abs_path = os.path.abspath(rel_path)
91
+ logger.info(f"Processing resource file: {abs_path}")
92
+ resource_dir = os.path.dirname(abs_path)
93
+
94
+ # Temporarily change to resource file's directory
95
+ # This helps with relative paths in the resource definition
96
+ os.chdir(resource_dir)
97
+
98
+ try:
99
+ with open(abs_path, 'r') as f:
100
+ path_lower = abs_path.lower()
101
+ if path_lower.endswith(".json"):
102
+ obj = json.load(f)
103
+ elif path_lower.endswith((".yaml", ".yml")):
104
+ obj = yaml.safe_load(f)
105
+ else:
106
+ logger.warning(
107
+ f"Skipping unsupported file type: {abs_path}"
108
+ )
109
+ continue
110
+
111
+ components = []
112
+ if isinstance(obj, list):
113
+ logger.info(f"Found {len(obj)} components in {abs_path}")
114
+ components.extend(obj)
115
+ elif isinstance(obj, dict):
116
+ components.append(obj)
117
+ else:
118
+ logger.warning(
119
+ f"Skipping unexpected object type in {abs_path}"
120
+ )
121
+ continue
122
+
123
+ for comp_obj in components:
124
+ # Ensure component object is a dictionary
125
+ if not isinstance(comp_obj, dict):
126
+ logger.warning(
127
+ f"Skipping non-dictionary item in {abs_path}"
128
+ )
129
+ continue
130
+
131
+ try:
132
+ if "deployed" in comp_obj:
133
+ # Remove deployment state if present
134
+ del comp_obj["deployed"]
135
+
136
+ component = self.kodexa_client.deserialize(comp_obj)
137
+ # Ensure correct org slug
138
+ component.org_slug = target_org_slug
139
+
140
+ logger.info(
141
+ "Deploying component %s:%s",
142
+ component.slug, component.version
143
+ )
144
+ log_details = component.deploy(update=True)
145
+ deployed_count += 1
146
+ for log_detail in log_details:
147
+ logger.info(log_detail)
148
+ except Exception as e:
149
+ comp_id = comp_obj.get('slug', 'unknown')
150
+ logger.error(
151
+ "Failed to deploy component %s from %s: %s",
152
+ comp_id, abs_path, e, exc_info=True
153
+ )
154
+ # Option: stop deployment on first error
155
+ # raise
156
+
157
+ except Exception as e:
158
+ logger.error(
159
+ "Failed to process resource file %s: %s",
160
+ abs_path, e, exc_info=True
161
+ )
162
+ finally:
163
+ # Return to manifest directory for next file
164
+ os.chdir(manifest_dir)
165
+
166
+ finally:
167
+ # Return to original working directory
168
+ os.chdir(original_cwd)
169
+
170
+ logger.info(
171
+ f"Deployment completed from manifest {manifest_path}. "
172
+ f"Deployed {deployed_count} components."
173
+ )
174
+
175
+ def undeploy_from_manifest(self, manifest_path: str,
176
+ org_slug: str | None = None):
177
+ """
178
+ Undeploys all resources listed in a manifest file.
179
+
180
+ Args:
181
+ manifest_path (str): The path to the manifest file.
182
+ org_slug (str | None): The organization slug to undeploy from.
183
+ If None, uses the default org from client.
184
+ """
185
+ target_org_slug = org_slug or self.kodexa_client.get_org_slug()
186
+ if not target_org_slug:
187
+ msg = "Organization slug must be provided or set in the client."
188
+ raise ValueError(msg)
189
+
190
+ logger.info(
191
+ f"Starting undeployment from manifest {manifest_path} "
192
+ f"for organization {target_org_slug}"
193
+ )
194
+ resource_paths = self.read_manifest(manifest_path)
195
+ abs_manifest_path = os.path.abspath(manifest_path)
196
+ manifest_dir = os.path.dirname(abs_manifest_path)
197
+ original_cwd = os.getcwd()
198
+ undeployed_count = 0
199
+
200
+ try:
201
+ # Change to manifest directory to resolve relative paths
202
+ os.chdir(manifest_dir)
203
+
204
+ for resource_pattern in resource_paths:
205
+ resource_files = glob.glob(resource_pattern, recursive=True)
206
+
207
+ if not resource_files:
208
+ logger.warning(
209
+ f"No files found matching pattern '{resource_pattern}' "
210
+ f"relative to {manifest_dir}"
211
+ )
212
+ continue
213
+
214
+ for rel_path in resource_files:
215
+ # Resolve absolute path based on current directory
216
+ abs_path = os.path.abspath(rel_path)
217
+ logger.info(f"Processing for undeployment: {abs_path}")
218
+
219
+ try:
220
+ with open(abs_path, 'r') as f:
221
+ path_lower = abs_path.lower()
222
+ if path_lower.endswith(".json"):
223
+ obj = json.load(f)
224
+ elif path_lower.endswith((".yaml", ".yml")):
225
+ obj = yaml.safe_load(f)
226
+ else:
227
+ logger.warning(
228
+ f"Skipping unsupported file type: {abs_path}"
229
+ )
230
+ continue
231
+
232
+ components = []
233
+ if isinstance(obj, list):
234
+ logger.info(f"Found {len(obj)} components in {abs_path}")
235
+ components.extend(obj)
236
+ elif isinstance(obj, dict):
237
+ components.append(obj)
238
+ else:
239
+ logger.warning(
240
+ f"Skipping unexpected object type in {abs_path}"
241
+ )
242
+ continue
243
+
244
+ for comp_obj in components:
245
+ # Ensure component object is a dictionary
246
+ if not isinstance(comp_obj, dict):
247
+ logger.warning(
248
+ f"Skipping non-dictionary item in {abs_path}"
249
+ )
250
+ continue
251
+
252
+ slug = comp_obj.get('slug')
253
+ version = comp_obj.get('version')
254
+
255
+ if not slug or not version:
256
+ logger.warning(
257
+ "Skipping component in %s (missing slug/version)",
258
+ abs_path
259
+ )
260
+ continue
261
+
262
+ try:
263
+ # Get component object to call undeploy
264
+ # Note: This assumes get_object method exists
265
+ # with appropriate parameters and return value
266
+ component = self.kodexa_client.get_object(
267
+ target_org_slug, slug, version
268
+ )
269
+ if component:
270
+ logger.info(
271
+ "Undeploying component %s:%s",
272
+ slug, version
273
+ )
274
+ component.undeploy()
275
+ undeployed_count += 1
276
+ else:
277
+ logger.warning(
278
+ "Component %s:%s not found in org %s",
279
+ slug, version, target_org_slug
280
+ )
281
+ except Exception as e:
282
+ logger.error(
283
+ "Failed to undeploy component %s:%s: %s",
284
+ slug, version, e, exc_info=True
285
+ )
286
+ # Option: stop on first error
287
+ # raise
288
+
289
+ except Exception as e:
290
+ logger.error(
291
+ "Failed to process file %s for undeployment: %s",
292
+ abs_path, e, exc_info=True
293
+ )
294
+
295
+ finally:
296
+ # Return to original working directory
297
+ os.chdir(original_cwd)
298
+
299
+ logger.info(
300
+ f"Undeployment completed from manifest {manifest_path}. "
301
+ f"Undeployed {undeployed_count} components."
302
+ )
303
+
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "kodexa"
3
- version = "7.4.414330611518"
3
+ version = "7.4.414560697286"
4
4
  description = "Python SDK for the Kodexa Platform"
5
5
  authors = ["Austin Redenbaugh <austin@kodexa.com>", "Philip Dodds <philip@kodexa.com>", "Romar Cablao <rcablao@kodexa.com>", "Amadea Paula Dodds <amadeapaula@kodexa.com>"]
6
6
  readme = "README.md"