@@ -519,6 +519,18 @@ def run(
519519 Uses embedded inference by default. Pass ``--connect`` to route
520520 through a running ``winml serve`` instance instead.
521521
522+ Exit Codes:
523+
524+ 0: Success
525+
526+ 1: General error
527+
528+ 2: Usage error — invalid input or arguments
529+
530+ 3: Model load failure
531+
532+ 4: Inference failure
533+
522534 Examples:
523535 \b
524536 # Image classification (shortcut)
@@ -547,17 +559,15 @@ def run(
547559 pipeline_kwargs : dict [str , Any ] = {}
548560 for p in params :
549561 if "=" not in p :
550- click .echo (f"Error: invalid --param format: '{ p } '. Use KEY=VALUE." , err = True )
551- ctx .exit (2 )
562+ raise click .UsageError (f"invalid --param format: '{ p } '. Use KEY=VALUE." )
552563 k , v = p .split ("=" , 1 )
553564 pipeline_kwargs [k ] = _parse_param_value (v )
554565
555566 # Parse --input entries (raw strings, coerced after model load)
556567 raw_inputs : dict [str , str ] = {}
557568 for inp in input_args :
558569 if "=" not in inp :
559- click .echo (f"Error: invalid --input format: '{ inp } '. Use NAME=VALUE." , err = True )
560- ctx .exit (2 )
570+ raise click .UsageError (f"invalid --input format: '{ inp } '. Use NAME=VALUE." )
561571 k , v = inp .split ("=" , 1 )
562572 raw_inputs [k ] = v
563573
@@ -566,17 +576,14 @@ def run(
566576 for fp in files :
567577 file_path = Path (fp )
568578 if not file_path .exists () or not file_path .is_file ():
569- click .echo (f"Error: file not found: { fp } " , err = True )
570- ctx .exit (2 )
579+ raise click .UsageError (f"file not found: { fp } " )
571580 file_bytes_list .append (file_path .read_bytes ())
572581
573582 if len (file_bytes_list ) > 1 :
574- click .echo (
575- f"Error: --file accepts only one file (got { len (file_bytes_list )} ). "
576- "Use --input for multiple file inputs (e.g. -I image_0=@a.jpg -I image_1=@b.jpg)." ,
577- err = True ,
583+ raise click .UsageError (
584+ f"--file accepts only one file (got { len (file_bytes_list )} ). "
585+ "Use --input for multiple file inputs (e.g. -I image_0=@a.jpg -I image_1=@b.jpg)."
578586 )
579- ctx .exit (2 )
580587
581588 # Check if any input was provided
582589 has_inputs = bool (file_bytes_list ) or text is not None or bool (raw_inputs )
@@ -619,8 +626,7 @@ def run(
619626 try :
620627 engine .load_schema_only (model , task = task , device = device , ep = ep )
621628 except (OSError , ValueError , RuntimeError ) as exc :
622- click .echo (f"Error loading model: { exc } " , err = True )
623- ctx .exit (3 )
629+ raise cli_utils .ModelLoadError (f"Error loading model: { exc } " ) from exc
624630 _print_schema (engine , output_format = output_format , output_path = output )
625631 return
626632
@@ -638,8 +644,7 @@ def run(
638644 allow_unsupported_nodes = allow_unsupported_nodes ,
639645 )
640646 except (OSError , ValueError , RuntimeError ) as exc :
641- click .echo (f"Error loading model: { exc } " , err = True )
642- ctx .exit (3 )
647+ raise cli_utils .ModelLoadError (f"Error loading model: { exc } " ) from exc
643648
644649 # No inputs: print hint and exit
645650 if not has_inputs :
@@ -651,33 +656,28 @@ def run(
651656 try :
652657 coerced_inputs = _coerce_inputs (raw_inputs , schema )
653658 except click .ClickException as exc :
654- click .echo (f"Error: { exc .format_message ()} " , err = True )
655- ctx .exit (2 )
659+ raise click .UsageError (exc .format_message ()) from exc
656660
657661 # Merge --file/--text shortcuts with --input
658662 try :
659663 inputs = _resolve_shortcuts (file_bytes_list , text , coerced_inputs , schema )
660664 except click .ClickException as exc :
661- click .echo (f"Error: { exc .format_message ()} " , err = True )
662- ctx .exit (2 )
665+ raise click .UsageError (exc .format_message ()) from exc
663666
664667 # Check input / -P collision (after shortcuts are resolved so that
665668 # --file and --text shortcut keys are included in the check)
666669 collision = set (inputs .keys ()) & set (pipeline_kwargs .keys ())
667670 if collision :
668671 key = sorted (collision )[0 ]
669- click .echo (
670- f"Error: '{ key } ' specified as both input and -P. "
671- f"Use --input for model inputs and -P for pipeline parameters." ,
672- err = True ,
672+ raise click .UsageError (
673+ f"'{ key } ' specified as both input and -P. "
674+ "Use --input for model inputs and -P for pipeline parameters."
673675 )
674- ctx .exit (2 )
675676
676677 try :
677678 prediction = engine .predict (inputs = inputs , ** pipeline_kwargs )
678679 except (ValueError , TypeError , RuntimeError , OSError ) as exc :
679- click .echo (f"Error during inference: { exc } " , err = True )
680- ctx .exit (4 )
680+ raise cli_utils .InferenceError (f"Error during inference: { exc } " ) from exc
681681
682682 _print_result (prediction .model_dump (), output_format = output_format , output_path = output )
683683
0 commit comments