""" Command-line interface for validation. Usage: python -m src.validation.cli [options] """ import sys import argparse import logging from pathlib import Path from datetime import datetime from ..common.database import DatabaseConfig, DatabaseConnection from ..common.logging_utils import setup_logger from .validator import OutputValidator def main(): """Main CLI entry point.""" parser = argparse.ArgumentParser( description='Validate Python sensor processing against MATLAB output', formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Examples: # Validate all sensors for a chain python -m src.validation.cli CU001 A # Validate specific sensor type python -m src.validation.cli CU001 A --type rsn # Validate with specific timestamps python -m src.validation.cli CU001 A --matlab-date 2025-10-12 --python-date 2025-10-13 # Custom tolerances for stricter validation python -m src.validation.cli CU001 A --abs-tol 1e-8 --rel-tol 1e-6 # Save report to file python -m src.validation.cli CU001 A --output validation_report.txt """ ) parser.add_argument('control_unit_id', help='Control unit identifier (e.g., CU001)') parser.add_argument('chain', help='Chain identifier (e.g., A, B)') parser.add_argument('--type', '--sensor-type', dest='sensor_type', choices=['rsn', 'tilt', 'atd-rl', 'atd-ll', 'atd-pl', 'atd-3del', 'atd-crl', 'atd-pcl', 'atd-tul', 'all'], default='all', help='Sensor type to validate (default: all)') parser.add_argument('--tilt-subtype', choices=['TLHR', 'BL', 'PL', 'KLHR'], help='Specific tilt sensor subtype') parser.add_argument('--matlab-date', help='Date for MATLAB data (YYYY-MM-DD)') parser.add_argument('--python-date', help='Date for Python data (YYYY-MM-DD)') parser.add_argument('--abs-tol', type=float, default=1e-6, help='Absolute tolerance (default: 1e-6)') parser.add_argument('--rel-tol', type=float, default=1e-4, help='Relative tolerance (default: 1e-4)') parser.add_argument('--max-rel-tol', type=float, default=0.01, help='Maximum acceptable relative difference (default: 0.01 = 1%%)') parser.add_argument('--output', '-o', help='Output file for validation report') parser.add_argument('--include-equivalent', action='store_true', help='Include equivalent (passing) comparisons in report') parser.add_argument('--verbose', '-v', action='store_true', help='Verbose output') parser.add_argument('--quiet', '-q', action='store_true', help='Quiet mode (errors only)') args = parser.parse_args() # Setup logging log_level = logging.INFO if args.verbose: log_level = logging.DEBUG elif args.quiet: log_level = logging.ERROR logger = setup_logger('validation', log_level=log_level) try: # Connect to database logger.info("Connecting to database...") db_config = DatabaseConfig() with DatabaseConnection(db_config) as conn: logger.info("Database connected") # Create validator validator = OutputValidator( conn, abs_tol=args.abs_tol, rel_tol=args.rel_tol, max_rel_tol=args.max_rel_tol ) # Run validation based on type logger.info(f"Starting validation for {args.control_unit_id}/{args.chain}") logger.info(f"Sensor type: {args.sensor_type}") logger.info(f"Tolerances: abs={args.abs_tol}, rel={args.rel_tol}, max_rel={args.max_rel_tol}") if args.sensor_type == 'all': report = validator.validate_all( args.control_unit_id, args.chain, matlab_timestamp=args.matlab_date, python_timestamp=args.python_date ) elif args.sensor_type == 'rsn': report = validator.validate_rsn( args.control_unit_id, args.chain, matlab_timestamp=args.matlab_date, python_timestamp=args.python_date ) elif args.sensor_type == 'tilt': if not args.tilt_subtype: logger.error("--tilt-subtype required for tilt validation") return 1 report = validator.validate_tilt( args.control_unit_id, args.chain, args.tilt_subtype, matlab_timestamp=args.matlab_date, python_timestamp=args.python_date ) elif args.sensor_type == 'atd-rl': report = validator.validate_atd_radial_link( args.control_unit_id, args.chain, matlab_timestamp=args.matlab_date, python_timestamp=args.python_date ) elif args.sensor_type == 'atd-ll': report = validator.validate_atd_load_link( args.control_unit_id, args.chain, matlab_timestamp=args.matlab_date, python_timestamp=args.python_date ) elif args.sensor_type == 'atd-pl': report = validator.validate_atd_pressure_link( args.control_unit_id, args.chain, matlab_timestamp=args.matlab_date, python_timestamp=args.python_date ) else: logger.error(f"Validation not yet implemented for {args.sensor_type}") return 1 # Generate report report_text = report.generate_report(include_equivalent=args.include_equivalent) # Print to console print(report_text) # Save to file if requested if args.output: report.save_report(args.output, include_equivalent=args.include_equivalent) logger.info(f"Report saved to {args.output}") # Return exit code based on validation result if report.is_valid(): logger.info("✓ Validation PASSED") return 0 else: logger.error("✗ Validation FAILED") return 1 except Exception as e: logger.error(f"Validation error: {e}", exc_info=True) return 1 if __name__ == '__main__': sys.exit(main())