kailash 0.2.0__py3-none-any.whl → 0.2.2__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.
@@ -54,7 +54,7 @@ Downstream Consumers:
54
54
 
55
55
  Examples:
56
56
  Optimization cycle template:
57
-
57
+
58
58
  >>> from kailash.workflow.templates import CycleTemplates
59
59
  >>> workflow = Workflow("optimization", "Quality Optimization")
60
60
  >>> workflow.add_node("processor", ProcessorNode())
@@ -66,9 +66,9 @@ Examples:
66
66
  ... convergence="quality > 0.95",
67
67
  ... max_iterations=100
68
68
  ... )
69
-
69
+
70
70
  Retry cycle with backoff:
71
-
71
+
72
72
  >>> cycle_id = CycleTemplates.retry_cycle(
73
73
  ... workflow,
74
74
  ... target_node="api_call",
@@ -76,9 +76,9 @@ Examples:
76
76
  ... backoff_strategy="exponential",
77
77
  ... success_condition="success == True"
78
78
  ... )
79
-
79
+
80
80
  Direct workflow integration:
81
-
81
+
82
82
  >>> # Templates extend Workflow class
83
83
  >>> workflow = Workflow("ml_training", "Model Training")
84
84
  >>> cycle_id = workflow.add_learning_cycle(
@@ -87,16 +87,16 @@ Examples:
87
87
  ... target_accuracy=0.98,
88
88
  ... early_stopping_patience=10
89
89
  ... )
90
-
90
+
91
91
  Custom template configuration:
92
-
92
+
93
93
  >>> # Numerical convergence with custom tolerance
94
94
  >>> cycle_id = workflow.add_convergence_cycle(
95
95
  ... processor_node="newton_raphson",
96
96
  ... tolerance=0.0001,
97
97
  max_iterations=1000
98
98
  )
99
-
99
+
100
100
  # Batch processing for large datasets
101
101
  cycle_id = workflow.add_batch_processing_cycle(
102
102
  processor_node="data_processor",
@@ -110,10 +110,10 @@ See Also:
110
110
  - :doc:`/examples/patterns` for comprehensive pattern examples
111
111
  """
112
112
 
113
- from typing import Dict, Any, List, Optional
114
- from dataclasses import dataclass
115
- import time
116
113
  import math
114
+ import time
115
+ from dataclasses import dataclass
116
+ from typing import Any, Dict, List, Optional
117
117
 
118
118
  from ..nodes.code import PythonCodeNode
119
119
  from . import Workflow
@@ -122,6 +122,7 @@ from . import Workflow
122
122
  @dataclass
123
123
  class CycleTemplate:
124
124
  """Configuration for a cycle template."""
125
+
125
126
  name: str
126
127
  description: str
127
128
  nodes: List[str]
@@ -133,7 +134,7 @@ class CycleTemplate:
133
134
 
134
135
  class CycleTemplates:
135
136
  """Collection of pre-built cycle templates for common patterns."""
136
-
137
+
137
138
  @staticmethod
138
139
  def optimization_cycle(
139
140
  workflow: Workflow,
@@ -141,14 +142,14 @@ class CycleTemplates:
141
142
  evaluator_node: str,
142
143
  convergence: str = "quality > 0.9",
143
144
  max_iterations: int = 50,
144
- cycle_id: Optional[str] = None
145
+ cycle_id: Optional[str] = None,
145
146
  ) -> str:
146
147
  """
147
148
  Add an optimization cycle pattern to workflow.
148
-
149
+
149
150
  Creates a cycle where a processor generates solutions and an evaluator
150
151
  assesses quality, continuing until convergence criteria is met.
151
-
152
+
152
153
  Args:
153
154
  workflow: Target workflow
154
155
  processor_node: Node that generates/improves solutions
@@ -156,10 +157,10 @@ class CycleTemplates:
156
157
  convergence: Convergence condition (e.g., "quality > 0.9")
157
158
  max_iterations: Maximum iterations before stopping
158
159
  cycle_id: Optional custom cycle identifier
159
-
160
+
160
161
  Returns:
161
162
  str: The cycle identifier for reference
162
-
163
+
163
164
  Example:
164
165
  >>> workflow = Workflow("optimization", "Optimization Example")
165
166
  >>> workflow.add_node("processor", PythonCodeNode(), code="...")
@@ -171,22 +172,22 @@ class CycleTemplates:
171
172
  """
172
173
  if cycle_id is None:
173
174
  cycle_id = f"optimization_cycle_{int(time.time())}"
174
-
175
+
175
176
  # Connect processor to evaluator
176
177
  workflow.connect(processor_node, evaluator_node)
177
-
178
+
178
179
  # Close the cycle with convergence condition
179
180
  workflow.connect(
180
- evaluator_node,
181
+ evaluator_node,
181
182
  processor_node,
182
183
  cycle=True,
183
184
  max_iterations=max_iterations,
184
185
  convergence_check=convergence,
185
- cycle_id=cycle_id
186
+ cycle_id=cycle_id,
186
187
  )
187
-
188
+
188
189
  return cycle_id
189
-
190
+
190
191
  @staticmethod
191
192
  def retry_cycle(
192
193
  workflow: Workflow,
@@ -194,14 +195,14 @@ class CycleTemplates:
194
195
  max_retries: int = 3,
195
196
  backoff_strategy: str = "exponential",
196
197
  success_condition: str = "success == True",
197
- cycle_id: Optional[str] = None
198
+ cycle_id: Optional[str] = None,
198
199
  ) -> str:
199
200
  """
200
201
  Add a retry cycle pattern to workflow.
201
-
202
+
202
203
  Creates a cycle that retries a node operation with configurable
203
204
  backoff strategy until success or max retries reached.
204
-
205
+
205
206
  Args:
206
207
  workflow: Target workflow
207
208
  target_node: Node to retry on failure
@@ -209,10 +210,10 @@ class CycleTemplates:
209
210
  backoff_strategy: Backoff strategy ("linear", "exponential", "fixed")
210
211
  success_condition: Condition that indicates success
211
212
  cycle_id: Optional custom cycle identifier
212
-
213
+
213
214
  Returns:
214
215
  str: The cycle identifier for reference
215
-
216
+
216
217
  Example:
217
218
  >>> workflow = Workflow("retry", "Retry Example")
218
219
  >>> workflow.add_node("api_call", PythonCodeNode(), code="...")
@@ -223,11 +224,11 @@ class CycleTemplates:
223
224
  """
224
225
  if cycle_id is None:
225
226
  cycle_id = f"retry_cycle_{int(time.time())}"
226
-
227
+
227
228
  # Create retry controller node
228
229
  retry_controller_id = f"{target_node}_retry_controller"
229
-
230
- retry_code = f'''
230
+
231
+ retry_code = f"""
231
232
  import time
232
233
  import random
233
234
 
@@ -270,13 +271,16 @@ result = {{
270
271
  "backoff_time": backoff_time,
271
272
  "retry_exhausted": attempt > {max_retries}
272
273
  }}
273
- '''
274
-
275
- workflow.add_node(retry_controller_id, PythonCodeNode(name=retry_controller_id, code=retry_code))
276
-
274
+ """
275
+
276
+ workflow.add_node(
277
+ retry_controller_id,
278
+ PythonCodeNode(name=retry_controller_id, code=retry_code),
279
+ )
280
+
277
281
  # Connect retry controller to target node
278
282
  workflow.connect(retry_controller_id, target_node)
279
-
283
+
280
284
  # Close the cycle with retry logic
281
285
  workflow.connect(
282
286
  target_node,
@@ -284,11 +288,11 @@ result = {{
284
288
  cycle=True,
285
289
  max_iterations=max_retries + 1,
286
290
  convergence_check=f"({success_condition}) or (retry_exhausted == True)",
287
- cycle_id=cycle_id
291
+ cycle_id=cycle_id,
288
292
  )
289
-
293
+
290
294
  return cycle_id
291
-
295
+
292
296
  @staticmethod
293
297
  def data_quality_cycle(
294
298
  workflow: Workflow,
@@ -296,14 +300,14 @@ result = {{
296
300
  validator_node: str,
297
301
  quality_threshold: float = 0.95,
298
302
  max_iterations: int = 10,
299
- cycle_id: Optional[str] = None
303
+ cycle_id: Optional[str] = None,
300
304
  ) -> str:
301
305
  """
302
306
  Add a data quality improvement cycle to workflow.
303
-
307
+
304
308
  Creates a cycle where data is cleaned and validated iteratively
305
309
  until quality threshold is met.
306
-
310
+
307
311
  Args:
308
312
  workflow: Target workflow
309
313
  cleaner_node: Node that cleans/improves data
@@ -311,10 +315,10 @@ result = {{
311
315
  quality_threshold: Minimum quality score to achieve
312
316
  max_iterations: Maximum cleaning iterations
313
317
  cycle_id: Optional custom cycle identifier
314
-
318
+
315
319
  Returns:
316
320
  str: The cycle identifier for reference
317
-
321
+
318
322
  Example:
319
323
  >>> workflow = Workflow("data_quality", "Data Quality Example")
320
324
  >>> workflow.add_node("cleaner", PythonCodeNode(), code="...")
@@ -325,10 +329,10 @@ result = {{
325
329
  """
326
330
  if cycle_id is None:
327
331
  cycle_id = f"data_quality_cycle_{int(time.time())}"
328
-
332
+
329
333
  # Connect cleaner to validator
330
334
  workflow.connect(cleaner_node, validator_node)
331
-
335
+
332
336
  # Close the cycle with quality threshold
333
337
  workflow.connect(
334
338
  validator_node,
@@ -336,11 +340,11 @@ result = {{
336
340
  cycle=True,
337
341
  max_iterations=max_iterations,
338
342
  convergence_check=f"quality_score >= {quality_threshold}",
339
- cycle_id=cycle_id
343
+ cycle_id=cycle_id,
340
344
  )
341
-
345
+
342
346
  return cycle_id
343
-
347
+
344
348
  @staticmethod
345
349
  def learning_cycle(
346
350
  workflow: Workflow,
@@ -349,14 +353,14 @@ result = {{
349
353
  target_accuracy: float = 0.95,
350
354
  max_epochs: int = 100,
351
355
  early_stopping_patience: int = 10,
352
- cycle_id: Optional[str] = None
356
+ cycle_id: Optional[str] = None,
353
357
  ) -> str:
354
358
  """
355
359
  Add a machine learning training cycle to workflow.
356
-
360
+
357
361
  Creates a cycle for iterative model training with early stopping
358
362
  based on validation performance.
359
-
363
+
360
364
  Args:
361
365
  workflow: Target workflow
362
366
  trainer_node: Node that trains the model
@@ -365,10 +369,10 @@ result = {{
365
369
  max_epochs: Maximum training epochs
366
370
  early_stopping_patience: Epochs to wait without improvement
367
371
  cycle_id: Optional custom cycle identifier
368
-
372
+
369
373
  Returns:
370
374
  str: The cycle identifier for reference
371
-
375
+
372
376
  Example:
373
377
  >>> workflow = Workflow("ml_training", "ML Training Example")
374
378
  >>> workflow.add_node("trainer", PythonCodeNode(), code="...")
@@ -379,11 +383,11 @@ result = {{
379
383
  """
380
384
  if cycle_id is None:
381
385
  cycle_id = f"learning_cycle_{int(time.time())}"
382
-
386
+
383
387
  # Create early stopping controller
384
388
  early_stop_controller_id = f"{trainer_node}_early_stop"
385
-
386
- early_stop_code = f'''
389
+
390
+ early_stop_code = f"""
387
391
  # Initialize early stopping state
388
392
  try:
389
393
  best_accuracy = best_accuracy
@@ -429,14 +433,17 @@ result = {{
429
433
  "early_stopped": early_stop,
430
434
  "training_complete": not should_continue
431
435
  }}
432
- '''
433
-
434
- workflow.add_node(early_stop_controller_id, PythonCodeNode(name=early_stop_controller_id, code=early_stop_code))
435
-
436
+ """
437
+
438
+ workflow.add_node(
439
+ early_stop_controller_id,
440
+ PythonCodeNode(name=early_stop_controller_id, code=early_stop_code),
441
+ )
442
+
436
443
  # Connect the training cycle
437
444
  workflow.connect(trainer_node, evaluator_node)
438
445
  workflow.connect(evaluator_node, early_stop_controller_id)
439
-
446
+
440
447
  # Close the cycle with early stopping logic
441
448
  workflow.connect(
442
449
  early_stop_controller_id,
@@ -444,35 +451,35 @@ result = {{
444
451
  cycle=True,
445
452
  max_iterations=max_epochs,
446
453
  convergence_check="training_complete == True",
447
- cycle_id=cycle_id
454
+ cycle_id=cycle_id,
448
455
  )
449
-
456
+
450
457
  return cycle_id
451
-
458
+
452
459
  @staticmethod
453
460
  def convergence_cycle(
454
461
  workflow: Workflow,
455
462
  processor_node: str,
456
463
  tolerance: float = 0.001,
457
464
  max_iterations: int = 1000,
458
- cycle_id: Optional[str] = None
465
+ cycle_id: Optional[str] = None,
459
466
  ) -> str:
460
467
  """
461
468
  Add a numerical convergence cycle to workflow.
462
-
469
+
463
470
  Creates a cycle that continues until successive iterations
464
471
  produce values within a specified tolerance.
465
-
472
+
466
473
  Args:
467
474
  workflow: Target workflow
468
475
  processor_node: Node that produces values to check for convergence
469
476
  tolerance: Maximum difference between iterations for convergence
470
477
  max_iterations: Maximum iterations before forced termination
471
478
  cycle_id: Optional custom cycle identifier
472
-
479
+
473
480
  Returns:
474
481
  str: The cycle identifier for reference
475
-
482
+
476
483
  Example:
477
484
  >>> workflow = Workflow("convergence", "Convergence Example")
478
485
  >>> workflow.add_node("processor", PythonCodeNode(), code="...")
@@ -482,11 +489,11 @@ result = {{
482
489
  """
483
490
  if cycle_id is None:
484
491
  cycle_id = f"convergence_cycle_{int(time.time())}"
485
-
492
+
486
493
  # Create convergence checker node
487
494
  convergence_checker_id = f"{processor_node}_convergence_checker"
488
-
489
- convergence_code = f'''
495
+
496
+ convergence_code = f"""
490
497
  import math
491
498
 
492
499
  # Initialize convergence state
@@ -526,13 +533,16 @@ result = {{
526
533
 
527
534
  # Update for next iteration
528
535
  previous_value = current_value
529
- '''
530
-
531
- workflow.add_node(convergence_checker_id, PythonCodeNode(name=convergence_checker_id, code=convergence_code))
532
-
536
+ """
537
+
538
+ workflow.add_node(
539
+ convergence_checker_id,
540
+ PythonCodeNode(name=convergence_checker_id, code=convergence_code),
541
+ )
542
+
533
543
  # Connect processor to convergence checker
534
544
  workflow.connect(processor_node, convergence_checker_id)
535
-
545
+
536
546
  # Close the cycle with convergence condition
537
547
  workflow.connect(
538
548
  convergence_checker_id,
@@ -540,35 +550,35 @@ previous_value = current_value
540
550
  cycle=True,
541
551
  max_iterations=max_iterations,
542
552
  convergence_check="converged == True",
543
- cycle_id=cycle_id
553
+ cycle_id=cycle_id,
544
554
  )
545
-
555
+
546
556
  return cycle_id
547
-
557
+
548
558
  @staticmethod
549
559
  def batch_processing_cycle(
550
560
  workflow: Workflow,
551
561
  processor_node: str,
552
562
  batch_size: int = 100,
553
563
  total_items: Optional[int] = None,
554
- cycle_id: Optional[str] = None
564
+ cycle_id: Optional[str] = None,
555
565
  ) -> str:
556
566
  """
557
567
  Add a batch processing cycle to workflow.
558
-
568
+
559
569
  Creates a cycle that processes data in batches, continuing
560
570
  until all items are processed.
561
-
571
+
562
572
  Args:
563
573
  workflow: Target workflow
564
574
  processor_node: Node that processes batches
565
575
  batch_size: Number of items to process per batch
566
576
  total_items: Total number of items to process (if known)
567
577
  cycle_id: Optional custom cycle identifier
568
-
578
+
569
579
  Returns:
570
580
  str: The cycle identifier for reference
571
-
581
+
572
582
  Example:
573
583
  >>> workflow = Workflow("batch", "Batch Processing Example")
574
584
  >>> workflow.add_node("processor", PythonCodeNode(), code="...")
@@ -578,11 +588,11 @@ previous_value = current_value
578
588
  """
579
589
  if cycle_id is None:
580
590
  cycle_id = f"batch_cycle_{int(time.time())}"
581
-
591
+
582
592
  # Create batch controller node
583
593
  batch_controller_id = f"{processor_node}_batch_controller"
584
-
585
- batch_code = f'''
594
+
595
+ batch_code = f"""
586
596
  # Initialize batch state
587
597
  try:
588
598
  batch_number = batch_number
@@ -625,19 +635,22 @@ result = {{
625
635
  # Update for next iteration
626
636
  start_index = end_index
627
637
  items_processed += actual_batch_size
628
- '''
629
-
630
- workflow.add_node(batch_controller_id, PythonCodeNode(name=batch_controller_id, code=batch_code))
631
-
638
+ """
639
+
640
+ workflow.add_node(
641
+ batch_controller_id,
642
+ PythonCodeNode(name=batch_controller_id, code=batch_code),
643
+ )
644
+
632
645
  # Connect batch controller to processor
633
646
  workflow.connect(batch_controller_id, processor_node)
634
-
647
+
635
648
  # Calculate max iterations based on total items
636
649
  if total_items is not None:
637
650
  max_iterations = math.ceil(total_items / batch_size) + 1
638
651
  else:
639
652
  max_iterations = 1000 # Default upper bound
640
-
653
+
641
654
  # Close the cycle with completion condition
642
655
  workflow.connect(
643
656
  processor_node,
@@ -645,9 +658,9 @@ items_processed += actual_batch_size
645
658
  cycle=True,
646
659
  max_iterations=max_iterations,
647
660
  convergence_check="all_processed == True",
648
- cycle_id=cycle_id
661
+ cycle_id=cycle_id,
649
662
  )
650
-
663
+
651
664
  return cycle_id
652
665
 
653
666
 
@@ -658,7 +671,7 @@ def add_optimization_cycle(
658
671
  evaluator_node: str,
659
672
  convergence: str = "quality > 0.9",
660
673
  max_iterations: int = 50,
661
- cycle_id: Optional[str] = None
674
+ cycle_id: Optional[str] = None,
662
675
  ) -> str:
663
676
  """Add an optimization cycle pattern to this workflow."""
664
677
  return CycleTemplates.optimization_cycle(
@@ -672,7 +685,7 @@ def add_retry_cycle(
672
685
  max_retries: int = 3,
673
686
  backoff_strategy: str = "exponential",
674
687
  success_condition: str = "success == True",
675
- cycle_id: Optional[str] = None
688
+ cycle_id: Optional[str] = None,
676
689
  ) -> str:
677
690
  """Add a retry cycle pattern to this workflow."""
678
691
  return CycleTemplates.retry_cycle(
@@ -686,7 +699,7 @@ def add_data_quality_cycle(
686
699
  validator_node: str,
687
700
  quality_threshold: float = 0.95,
688
701
  max_iterations: int = 10,
689
- cycle_id: Optional[str] = None
702
+ cycle_id: Optional[str] = None,
690
703
  ) -> str:
691
704
  """Add a data quality improvement cycle to this workflow."""
692
705
  return CycleTemplates.data_quality_cycle(
@@ -701,11 +714,17 @@ def add_learning_cycle(
701
714
  target_accuracy: float = 0.95,
702
715
  max_epochs: int = 100,
703
716
  early_stopping_patience: int = 10,
704
- cycle_id: Optional[str] = None
717
+ cycle_id: Optional[str] = None,
705
718
  ) -> str:
706
719
  """Add a machine learning training cycle to this workflow."""
707
720
  return CycleTemplates.learning_cycle(
708
- self, trainer_node, evaluator_node, target_accuracy, max_epochs, early_stopping_patience, cycle_id
721
+ self,
722
+ trainer_node,
723
+ evaluator_node,
724
+ target_accuracy,
725
+ max_epochs,
726
+ early_stopping_patience,
727
+ cycle_id,
709
728
  )
710
729
 
711
730
 
@@ -714,7 +733,7 @@ def add_convergence_cycle(
714
733
  processor_node: str,
715
734
  tolerance: float = 0.001,
716
735
  max_iterations: int = 1000,
717
- cycle_id: Optional[str] = None
736
+ cycle_id: Optional[str] = None,
718
737
  ) -> str:
719
738
  """Add a numerical convergence cycle to this workflow."""
720
739
  return CycleTemplates.convergence_cycle(
@@ -727,7 +746,7 @@ def add_batch_processing_cycle(
727
746
  processor_node: str,
728
747
  batch_size: int = 100,
729
748
  total_items: Optional[int] = None,
730
- cycle_id: Optional[str] = None
749
+ cycle_id: Optional[str] = None,
731
750
  ) -> str:
732
751
  """Add a batch processing cycle to this workflow."""
733
752
  return CycleTemplates.batch_processing_cycle(
@@ -741,4 +760,4 @@ Workflow.add_retry_cycle = add_retry_cycle
741
760
  Workflow.add_data_quality_cycle = add_data_quality_cycle
742
761
  Workflow.add_learning_cycle = add_learning_cycle
743
762
  Workflow.add_convergence_cycle = add_convergence_cycle
744
- Workflow.add_batch_processing_cycle = add_batch_processing_cycle
763
+ Workflow.add_batch_processing_cycle = add_batch_processing_cycle