88import click
99from pydantic import ValidationError
1010
11+ from antipasta .cli .validation_utils import get_metric_constraints
1112from antipasta .core .config import AntipastaConfig
13+ from antipasta .core .metric_models import MetricThresholds
1214
1315
14- def validate_positive_int (value : str , min_val : int = 1 , max_val : int | None = None ) -> int :
15- """Validate a positive integer within optional range."""
16- try :
17- num = int (value )
18- if num < min_val :
19- raise click .BadParameter (f"Value must be at least { min_val } " )
20- if max_val is not None and num > max_val :
21- raise click .BadParameter (f"Value must be at most { max_val } " )
22- return num
23- except ValueError as e :
24- raise click .BadParameter ("Must be a valid integer" ) from e
16+ def validate_with_pydantic (metric_type : str , value : str ) -> float :
17+ """Validate a metric value using Pydantic model.
2518
19+ Args:
20+ metric_type: The metric type being validated
21+ value: String value to validate
2622
27- def validate_positive_float (
28- value : str , min_val : float = 0.0 , max_val : float | None = None
29- ) -> float :
30- """Validate a positive float within optional range."""
23+ Returns:
24+ Validated numeric value
25+
26+ Raises:
27+ click.BadParameter: If validation fails
28+ """
3129 try :
3230 num = float (value )
33- if num < min_val :
34- raise click .BadParameter (f"Value must be at least { min_val } " )
35- if max_val is not None and num > max_val :
36- raise click .BadParameter (f"Value must be at most { max_val } " )
31+ # Use Pydantic validation
32+ MetricThresholds (** {metric_type : num })
3733 return num
38- except ValueError as e :
39- raise click .BadParameter ("Must be a valid number" ) from e
34+ except ValidationError as e :
35+ # Extract first error message
36+ if e .errors ():
37+ err = e .errors ()[0 ]
38+ err_type = err .get ('type' , '' )
39+ ctx = err .get ('ctx' , {})
40+
41+ if 'greater_than_equal' in err_type :
42+ raise click .BadParameter (f"Value must be >= { ctx .get ('ge' , 0 )} " )
43+ elif 'less_than_equal' in err_type :
44+ raise click .BadParameter (f"Value must be <= { ctx .get ('le' , 'max' )} " )
45+ elif err_type == 'int_type' :
46+ raise click .BadParameter (f"Must be an integer" )
47+
48+ raise click .BadParameter (str (e ))
49+ except ValueError :
50+ raise click .BadParameter ("Must be a valid number" )
4051
4152
4253def prompt_with_validation (
@@ -98,25 +109,29 @@ def generate(output: Path, non_interactive: bool) -> None:
98109 click .echo ("\n Let's set up your code quality thresholds:" )
99110 click .echo ("-" * 40 )
100111
112+ # Get constraints from Pydantic model
113+ cc_min , cc_max = get_metric_constraints ('cyclomatic_complexity' )
101114 max_cyclomatic = prompt_with_validation (
102115 "Maximum cyclomatic complexity per function" ,
103116 default = 10 ,
104- validator = lambda v : validate_positive_int ( v , min_val = 1 , max_val = 50 ),
105- help_text = "ℹ️ Range: 1-50 (lower is stricter). Recommended: 10" ,
117+ validator = lambda v : validate_with_pydantic ( 'cyclomatic_complexity' , v ),
118+ help_text = f "ℹ️ Range: { cc_min } - { cc_max } (lower is stricter). Recommended: 10" ,
106119 )
107120
121+ cog_min , cog_max = get_metric_constraints ('cognitive_complexity' )
108122 max_cognitive = prompt_with_validation (
109123 "Maximum cognitive complexity per function" ,
110124 default = 15 ,
111- validator = lambda v : validate_positive_int ( v , min_val = 1 , max_val = 100 ),
112- help_text = "ℹ️ Range: 1-100 (lower is stricter). Recommended: 15" ,
125+ validator = lambda v : validate_with_pydantic ( 'cognitive_complexity' , v ),
126+ help_text = f "ℹ️ Range: { cog_min } - { cog_max } (lower is stricter). Recommended: 15" ,
113127 )
114128
129+ mi_min , mi_max = get_metric_constraints ('maintainability_index' )
115130 min_maintainability = prompt_with_validation (
116131 "Minimum maintainability index" ,
117132 default = 50 ,
118- validator = lambda v : validate_positive_int ( v , min_val = 0 , max_val = 100 ),
119- help_text = "ℹ️ Range: 0-100 (higher is stricter). Recommended: 50" ,
133+ validator = lambda v : validate_with_pydantic ( 'maintainability_index' , v ),
134+ help_text = f "ℹ️ Range: { mi_min } - { mi_max } (higher is stricter). Recommended: 50" ,
120135 )
121136
122137 # Ask about advanced metrics
@@ -135,25 +150,28 @@ def generate(output: Path, non_interactive: bool) -> None:
135150 click .echo ("\n Advanced Halstead metrics:" )
136151 click .echo ("-" * 40 )
137152
153+ hv_min , hv_max = get_metric_constraints ('halstead_volume' )
138154 defaults_dict ["max_halstead_volume" ] = prompt_with_validation (
139155 "Maximum Halstead volume" ,
140156 default = 1000 ,
141- validator = lambda v : validate_positive_float ( v , min_val = 1 , max_val = 100000 ),
142- help_text = "ℹ️ Range: 1-100000 . Measures program size. Recommended: 1000" ,
157+ validator = lambda v : validate_with_pydantic ( 'halstead_volume' , v ),
158+ help_text = f "ℹ️ Range: { hv_min } - { hv_max } . Measures program size. Recommended: 1000" ,
143159 )
144160
161+ hd_min , hd_max = get_metric_constraints ('halstead_difficulty' )
145162 defaults_dict ["max_halstead_difficulty" ] = prompt_with_validation (
146163 "Maximum Halstead difficulty" ,
147164 default = 10 ,
148- validator = lambda v : validate_positive_float ( v , min_val = 0.1 , max_val = 100 ),
149- help_text = "ℹ️ Range: 0.1-100 . Measures error proneness. Recommended: 10" ,
165+ validator = lambda v : validate_with_pydantic ( 'halstead_difficulty' , v ),
166+ help_text = f "ℹ️ Range: { hd_min } - { hd_max } . Measures error proneness. Recommended: 10" ,
150167 )
151168
169+ he_min , he_max = get_metric_constraints ('halstead_effort' )
152170 defaults_dict ["max_halstead_effort" ] = prompt_with_validation (
153171 "Maximum Halstead effort" ,
154172 default = 10000 ,
155- validator = lambda v : validate_positive_float ( v , min_val = 1 , max_val = 1000000 ),
156- help_text = "ℹ️ Range: 1-1000000 . Measures implementation time. Recommended: 10000" ,
173+ validator = lambda v : validate_with_pydantic ( 'halstead_effort' , v ),
174+ help_text = f "ℹ️ Range: { he_min } - { he_max } . Measures implementation time. Recommended: 10000" ,
157175 )
158176 else :
159177 # Use defaults for advanced metrics
0 commit comments