cursus.validation.script_testing¶
Simplified Script Testing Framework
This module provides a streamlined script testing framework that extends existing cursus infrastructure instead of reimplementing it. The approach eliminates over-engineering by directly reusing DAGConfigFactory, StepCatalog, and UnifiedDependencyResolver components.
This simplified implementation reduces code from 4,200 lines across 17 modules to 800-1,000 lines across 5 modules while maintaining all functionality and addressing the 3 key user stories:
US1: Individual Script Functionality Testing
US2: Data Transfer and Compatibility Testing
US3: DAG-Guided End-to-End Testing
Key Features: - Maximum infrastructure reuse (95% of existing cursus components) - Config-based phantom script elimination - Package dependency management (the one valid complexity) - Comprehensive result formatting - Interactive input collection extending DAGConfigFactory patterns
- Main API Functions:
run_dag_scripts: Main entry point for DAG-guided script testing
- Core Components:
ScriptTestingInputCollector: Extends DAGConfigFactory for input collection ResultFormatter: Comprehensive result formatting (preserved from original) ScriptTestResult: Simple result model for script execution
- run_dag_scripts(dag, config_path, test_workspace_dir='test/integration/script_testing', step_catalog=None, use_dependency_resolution=True)[source]¶
ENHANCED: Run scripts with ScriptExecutionRegistry integration and message passing.
This function now uses the ScriptExecutionRegistry for central state coordination, enabling intelligent dependency resolution and automatic message passing between script executions.
- Parameters:
dag (PipelineDAG) – PipelineDAG instance defining the pipeline structure
config_path (str) – Path to pipeline configuration JSON file for script validation
test_workspace_dir (str) – Directory for test workspace and script discovery
step_catalog (StepCatalog | None) – Optional StepCatalog instance (will create if not provided)
use_dependency_resolution (bool) – Whether to use two-phase dependency resolution
- Returns:
Dictionary with execution results and metadata
- Return type:
Example
>>> from cursus.validation.script_testing import run_dag_scripts >>> from cursus.api.dag.base_dag import PipelineDAG >>> >>> dag = PipelineDAG.from_json("configs/xgboost_training.json") >>> results = run_dag_scripts( ... dag=dag, ... config_path="pipeline_config/config_NA_xgboost_AtoZ.json" ... ) >>> print(f"Pipeline success: {results['pipeline_success']}")
- class ScriptTestingInputCollector(dag, config_path, registry=None, use_dependency_resolution=True)[source]¶
Bases:
objectEnhanced with Direct Registry Integration for field value population.
This class reuses the existing 600+ lines of proven interactive collection patterns and integrates directly with ScriptExecutionRegistry for: - Registry-coordinated field population - Message passing between script executions - Dynamic environment variable generation - Dependency-aware path resolution
- collect_script_inputs_for_dag()[source]¶
Enhanced collection with Direct Registry Integration.
This method supports three modes: 1. Registry-integrated collection (NEW) 2. Two-phase dependency resolution 3. Manual collection (backward compatibility)
- class ResultFormatter(format_options=None)[source]¶
Bases:
objectComprehensive result formatting utilities for script testing results.
Provides multiple output formats and visualization options for script execution results, including console output, JSON, CSV, and HTML reports.
Key features: 1. Multiple output formats (console, JSON, CSV, HTML) 2. Customizable formatting options 3. Summary and detailed reporting 4. Error highlighting and analysis 5. Performance metrics visualization
- format_options¶
Dictionary of formatting configuration options
- format_execution_results(results, format_type='console')[source]¶
Format complete execution results in specified format.
- format_script_result(script_result, format_type='console')[source]¶
Format individual script result.
- Parameters:
script_result (ScriptTestResult) – ScriptTestResult to format
format_type (str) – Output format (“console”, “json”, “summary”)
- Returns:
Formatted script result string
- Return type:
- class ScriptTestResult(success, output_files=None, error_message=None, execution_time=None)[source]¶
Bases:
objectSimple result model for script execution.
- class ScriptExecutionRegistry(dag, step_catalog=None)[source]¶
Bases:
objectCentral state coordinator that integrates both layers:
Layer 1 (script_dependency_matcher): DAG-level orchestration Layer 2 (script_input_resolver): Script-level resolution
Registry Role: - Maintains DAG execution state - Coordinates message passing between layers - Provides state interface for both layers - Ensures sequential consistency
- clear_registry()[source]¶
Clear registry for testing or new execution.
Resets all state while preserving DAG and step catalog references.
- commit_execution_results(node_name, execution_result)[source]¶
Integration Point 6: Store execution results for message passing.
API layer calls this after script execution to update state.
- Parameters:
node_name (str) – Name of the executed node
execution_result (ScriptTestResult) – Result of script execution
- get_dependency_outputs_for_node(node_name)[source]¶
Integration Point 2: Provide dependency outputs for message passing.
script_dependency_matcher calls this to get outputs from completed dependencies.
- get_node_config_for_resolver(node_name)[source]¶
Integration Point 3: Provide node config to script_input_resolver.
script_input_resolver calls this to get base configuration for a node.
- get_ready_node_inputs(node_name)[source]¶
Integration Point 5: Provide complete inputs for script execution.
API layer calls this to get final inputs for script execution.
- initialize_from_dependency_matcher(prepared_data)[source]¶
Integration Point 1: Receive prepared data from script_dependency_matcher.
script_dependency_matcher calls this to initialize registry state.
- sequential_state_update()[source]¶
Generator that yields nodes in topological order with updated state.
This ensures: - Dependencies are processed before dependents - State updates are sequential and consistent - Message passing happens in correct order
- Yields:
Tuple of (node_name, updated_node_state) for each node in execution order
- class DAGStateConsistency[source]¶
Bases:
objectEnsures state consistency during sequential message passing.
Guarantees: 1. Dependencies are always processed before dependents (topological order) 2. Node state is only updated when all dependencies are completed 3. Message passing only uses outputs from completed nodes 4. State updates are atomic and consistent
- static ensure_state_consistency(registry, node_name)[source]¶
Ensure node state is consistent before execution.
- Parameters:
registry (ScriptExecutionRegistry) – ScriptExecutionRegistry instance
node_name (str) – Name of the node to validate
- Raises:
RuntimeError – If state is inconsistent
- static validate_execution_order(dag, execution_order)[source]¶
Validate that execution order respects dependency constraints.
- Parameters:
dag (PipelineDAG) – PipelineDAG instance
execution_order (List[str]) – List of node names in execution order
- Raises:
ValueError – If execution order violates dependency constraints
- create_script_execution_registry(dag, step_catalog=None)[source]¶
Factory function to create a ScriptExecutionRegistry instance.
- Parameters:
dag (PipelineDAG) – PipelineDAG instance defining the pipeline structure
step_catalog (StepCatalog | None) – Optional StepCatalog instance (will create if not provided)
- Returns:
Configured ScriptExecutionRegistry instance
- Return type:
- resolve_script_dependencies(dag, config_path, step_catalog, registry=None)[source]¶
SIMPLIFIED: Two-phase dependency resolution with optional registry integration.
When registry is provided, uses registry coordination for state management. When registry is None, uses legacy standalone mode for backward compatibility.
- Parameters:
dag (PipelineDAG) – PipelineDAG defining script execution order and dependencies
config_path (str) – Path to configuration file for config-based extraction
step_catalog (StepCatalog) – For loading specifications and contracts
registry – Optional ScriptExecutionRegistry for state coordination
- Returns:
Complete user inputs ready for script execution
- Return type:
- prepare_script_testing_inputs(dag, config_path, step_catalog)[source]¶
Phase 1: Automatic dependency analysis using pipeline assembler patterns.
DIRECT REUSE of PipelineAssembler._propagate_messages() algorithm.
- Parameters:
dag (PipelineDAG) – PipelineDAG defining script execution order and dependencies
config_path (str) – Path to configuration file for config-based extraction
step_catalog (StepCatalog) – For loading specifications and contracts
- Returns:
Prepared data structure containing dependency matches and config data
- Return type:
- collect_user_inputs_with_dependency_resolution(prepared_data)[source]¶
Phase 2: Interactive input collection with automatic dependency resolution.
Mirrors PipelineAssembler._propagate_messages() + StepBuilder._get_inputs() patterns.
- validate_dependency_resolution_result(user_inputs)[source]¶
Validate the result of dependency resolution.
- get_dependency_resolution_summary(prepared_data, user_inputs)[source]¶
Generate a summary of the dependency resolution process.
- resolve_script_inputs_using_step_patterns(node_name, spec, resolved_dependencies, step_catalog)[source]¶
Script input resolution adapted from StepBuilder._get_inputs() patterns.
DIRECT ADAPTATION of step builder input resolution logic for script testing. This function mirrors the same patterns used in step builders for input resolution, providing consistent behavior between pipeline steps and script testing.
- Parameters:
node_name (str) – Name of the script/node
spec (StepInterface) – Step specification with dependencies and outputs
resolved_dependencies (Dict[str, str]) – Dictionary of resolved dependency paths
step_catalog (StepCatalog) – Step catalog for contract loading
- Returns:
Dictionary mapping logical dependency names to actual script input paths
- Return type:
Example
>>> spec = step_catalog.load_spec_class('DataPreprocessing') >>> resolved_deps = {'training_data': '/data/input/train.csv'} >>> script_inputs = resolve_script_inputs_using_step_patterns( ... 'DataPreprocessing', spec, resolved_deps, step_catalog ... ) >>> print(script_inputs) {'training_data': '/data/input/train.csv'}
- adapt_step_input_patterns_for_scripts(node_name, inputs, step_catalog)[source]¶
Adapt step builder input patterns for script testing.
DIRECT ADAPTATION of step builder input resolution patterns. This function provides the same input validation and transformation patterns used in step builders, ensuring consistency across the system.
- Parameters:
node_name (str) – Name of the script/node
inputs (Dict[str, Any]) – Dictionary of input data to process
step_catalog (StepCatalog) – Step catalog for specification and contract loading
- Returns:
Dictionary mapping logical names to actual script input paths
- Raises:
ValueError – If specification or contract not found, or required inputs missing
- Return type:
Example
>>> inputs = {'training_data': '/data/train.csv', 'model_config': '/config/model.json'} >>> script_inputs = adapt_step_input_patterns_for_scripts( ... 'XGBoostTraining', inputs, step_catalog ... ) >>> print(script_inputs) {'training_data': '/data/train.csv', 'model_config': '/config/model.json'}
- validate_script_input_resolution(node_name, script_inputs, step_catalog)[source]¶
Validate script input resolution using step builder validation patterns.
This function applies the same validation logic used in step builders to ensure script inputs are properly resolved and valid.
- Parameters:
node_name (str) – Name of the script/node
script_inputs (Dict[str, str]) – Dictionary of resolved script inputs
step_catalog (StepCatalog) – Step catalog for specification loading
- Returns:
True if validation passes, False otherwise
- Return type:
Example
>>> script_inputs = {'training_data': '/data/train.csv'} >>> is_valid = validate_script_input_resolution( ... 'DataPreprocessing', script_inputs, step_catalog ... ) >>> print(is_valid) True
- get_script_input_resolution_summary(node_name, script_inputs, step_catalog)[source]¶
Generate a summary of script input resolution for debugging and monitoring.
- Parameters:
node_name (str) – Name of the script/node
script_inputs (Dict[str, str]) – Dictionary of resolved script inputs
step_catalog (StepCatalog) – Step catalog for specification loading
- Returns:
Dictionary with resolution summary information
- Return type:
Example
>>> script_inputs = {'training_data': '/data/train.csv', 'config': '/config/model.json'} >>> summary = get_script_input_resolution_summary( ... 'XGBoostTraining', script_inputs, step_catalog ... ) >>> print(summary['total_inputs']) 2
- transform_logical_names_to_actual_paths(logical_inputs, node_name, step_catalog)[source]¶
Transform logical dependency names to actual file paths using contract patterns.
This function applies the same logical-to-actual path transformation used in step builders, ensuring consistent path resolution across the system.
- Parameters:
logical_inputs (Dict[str, str]) – Dictionary mapping logical names to paths
node_name (str) – Name of the script/node
step_catalog (StepCatalog) – Step catalog for contract loading
- Returns:
Dictionary mapping logical names to actual file paths
- Return type:
Example
>>> logical_inputs = {'training_data': '/container/input/data'} >>> actual_paths = transform_logical_names_to_actual_paths( ... logical_inputs, 'DataPreprocessing', step_catalog ... ) >>> print(actual_paths) {'training_data': '/opt/ml/input/data/training_data.csv'}
- execute_single_script(script_path, input_paths, output_paths, environ_vars, job_args)[source]¶
Execute a single script with the fixed signature and dependency management.
This function handles the one legitimate complexity in script testing: package dependency management (scripts import packages that need installation).
- Parameters:
script_path (str) – Path to the script file
input_paths (Dict[str, str]) – Input paths from InputCollector (contract-based logical names)
output_paths (Dict[str, str]) – Output paths from InputCollector (contract-based logical names)
environ_vars (Dict[str, str]) – Environment variables from config
job_args – Job arguments from config (argparse.Namespace)
- Returns:
ScriptTestResult with execution outcome
- Return type:
- install_script_dependencies(script_path)[source]¶
Install package dependencies for script execution.
This is the ONE valid complexity in script testing - scripts import packages that need to be installed before execution. In SageMaker pipeline, this was isolated as an environment.
- Parameters:
script_path (str) – Path to the script file
- collect_script_inputs_using_dag_factory(dag, config_path)[source]¶
Collect script inputs by extending DAGConfigFactory patterns.
This function reuses the existing 600+ lines of proven interactive collection patterns instead of reimplementing them.
- Parameters:
dag (PipelineDAG) – PipelineDAG instance
config_path (str) – Path to configuration file for script validation
- Returns:
Dictionary mapping script names to their input configurations
- Return type:
- get_validated_scripts_from_config(dag, configs)[source]¶
Get only scripts with actual entry points from config (eliminates phantom scripts).
This addresses the phantom script issue by using config-based validation to ensure only scripts with actual entry points are discovered.
- execute_scripts_in_order(execution_order, user_inputs)[source]¶
DRAMATICALLY SIMPLIFIED: Execute scripts with complete pre-resolved inputs.
All complexity (message passing, dependency matching, config extraction) is handled in input collection phase.
- install_package(package_name)[source]¶
Install a package using pip.
- Parameters:
package_name (str) – Name of the package to install
- import_and_execute_script(script_path, input_paths, output_paths, environ_vars, job_args)[source]¶
Import and execute a script with the fixed signature.
Uses the testability pattern: main(input_paths, output_paths, environ_vars, job_args)
- Parameters:
script_path (str) – Path to the script file
input_paths (Dict[str, str]) – Input paths from InputCollector (contract-based logical names)
output_paths (Dict[str, str]) – Output paths from InputCollector (contract-based logical names)
environ_vars (Dict[str, str]) – Environment variables from config
job_args – Job arguments from config (argparse.Namespace)
- Returns:
Dictionary with execution results
- Return type:
- validate_dag_and_config(dag, config_path)[source]¶
Validate DAG and config path inputs.
- Parameters:
dag – PipelineDAG instance
config_path (str) – Path to configuration file
- Returns:
Dictionary with validation results
- Raises:
ValueError – If validation fails
- Return type:
- create_default_paths(script_name, base_dir='test')[source]¶
Create default input and output paths for a script.
- merge_script_configs(base_config, script_config)[source]¶
Merge base configuration with script-specific configuration.
Modules
Simplified Script Testing API |
|
Script Testing Input Collector |
|
Result Formatter |
|
Two-Phase Script Dependency Resolution System |
|
Script Execution Registry |
|
Script Input Resolution Pattern Adaptation |
|
Script Testing Utilities |