66from pydantic import ValidationError as PydanticValidationError
77from prich .constants import PRICH_DIR_NAME
88from prich .models .template import CommandStep , PythonStep
9- from prich .core .file_scope import classify_path
9+ from prich .core .file_scope import classify_path , normalize_path
1010from prich .core .loaders import find_template_files , load_template_model , get_env_vars , _load_yaml
1111from prich .core .utils import console_print , shorten_path , get_prich_dir , is_just_filename , get_cwd_dir , get_home_dir
1212
@@ -21,14 +21,16 @@ def template_model_doctor(template_yaml: dict, model_load_error: PydanticValidat
2121 if template_yaml and err .get ("loc" ):
2222 # hide extra layering
2323 if err .get ("loc" )[0 ] == "steps" :
24- if err .get ("loc" )[2 ] in ['llm' , 'command' , 'python' , 'render' ]:
24+ if len ( err . get ( "loc" )) >= 3 and err .get ("loc" )[2 ] in ['llm' , 'command' , 'python' , 'render' ]:
2525 details = err .get ("loc" )[2 ]
2626 err ['loc' ] = tuple (err .get ("loc" )[:2 ] + err .get ("loc" )[3 :])
2727
2828 trace_dir = template_yaml .copy ()
2929 loc_list = err .get ("loc" )[:- 1 ] if len (err .get ("loc" )) > 1 else err .get ("loc" )
3030 for x in loc_list :
3131 try :
32+ if trace_dir [x ] is None :
33+ break
3234 trace_dir = trace_dir [x ]
3335 except Exception :
3436 break
@@ -45,8 +47,10 @@ def template_model_doctor(template_yaml: dict, model_load_error: PydanticValidat
4547 template_overview = re .sub ("(\\ .\\ .\\ .)" , f"[yellow]+{ err .get ('loc' )[- 1 ]} : ...[/yellow]\n \\ 1" ,
4648 template_overview , count = 1 )
4749 else :
50+ if 'Input tag ' in err .get ('msg' ):
51+ err ["msg" ] = err ['msg' ].replace ("Input tag " , "Field value " ).replace (" any of the expected tags" , " any of the expected values" )
4852 if 'Input should be' in err .get ('msg' ):
49- err ["msg" ] = err ['msg' ].replace ("Input should be" , "Field value should be" )
53+ err ["msg" ] = err ['msg' ].replace ("Input should be " , "Field value should be " )
5054 highligh_block = err .get ('loc' )[- 1 ] if isinstance (err .get ('loc' )[- 1 ], str ) else err .get ('loc' )[- 2 ]
5155 template_overview = re .sub (f"([\n ]*(?:\\ s+)|^)({ highligh_block } )(:)" , "\\ 1[red]\\ 2[/red]\\ 3" ,
5256 template_overview , count = 1 )
@@ -92,7 +96,7 @@ def template_model_doctor(template_yaml: dict, model_load_error: PydanticValidat
9296 else :
9397 doc = "See Template Content Documentation https://oleks-dev.github.io/prich/reference/template/content/"
9498 err_loc_string = re .sub (f"({ err .get ('loc' )[- 1 ]} )$" , "[red]\\ 1[/red]" , err_loc_string )
95- found_issues_list .append (f"""{ len (found_issues_list )+ 1 } . [red]{ err .get ('msg' )} [/red] '[white]{ err_loc_string } [/white]':\n [white]{ template_overview } [/white]{ doc } """ )
99+ found_issues_list .append (f"""{ len (found_issues_list )+ 1 } . [red]{ err .get ('msg' )} [/red] at '[white]{ err_loc_string } [/white]':\n [white]{ template_overview } [/white]{ doc } """ )
96100 return found_issues_list
97101
98102
@@ -111,7 +115,10 @@ def validate_templates(template_id: str, validate_file: Path, global_only: bool,
111115 if validate_file and (global_only or local_only or template_id ):
112116 raise click .ClickException (f"When YAML file is selected it doesn't combine with local, global, or id options, use: 'prich validate --file ./{ PRICH_DIR_NAME } /templates/test-template/test-template.yaml'" )
113117
114- if validate_file and not validate_file .exists ():
118+ if validate_file :
119+ validate_file = normalize_path (validate_file , cwd = get_cwd_dir ())
120+
121+ if validate_file and (not validate_file .exists () or not validate_file .is_file ()):
115122 raise click .ClickException (f"Failed to find { validate_file } template file." )
116123
117124 # Load Template Files
@@ -154,10 +161,9 @@ def validate_templates(template_id: str, validate_file: Path, global_only: bool,
154161 model_failures_count = 0
155162 output = []
156163 try :
157- if template_file .is_file ():
158- template_yaml = _load_yaml (template_file )
159- template_id = template_yaml .get ("id" ) if template_yaml else None
160- template_name = template_yaml .get ("name" ) if template_yaml else None
164+ template_yaml = _load_yaml (template_file )
165+ template_id = template_yaml .get ("id" ) if template_yaml else None
166+ template_name = template_yaml .get ("name" ) if template_yaml else None
161167 try :
162168 template = load_template_model (template_file )
163169 except PydanticValidationError as e :
@@ -169,8 +175,18 @@ def validate_templates(template_id: str, validate_file: Path, global_only: bool,
169175 raise click .ClickException (f"1. [red]{ str (e )} [/red]" )
170176 if template .venv in ["isolated" , "shared" ]:
171177 venv_folder = (Path (template .folder ) / "scripts" ) if template .venv == "isolated" else get_prich_dir () / "venv"
178+ python_steps = [step for step in template .steps if step .type == 'python' ]
179+ if not python_steps :
180+ extra_note = ". There are no steps with type 'python' found, if python is not used you can remove the 'venv' parameter from the template"
181+ else :
182+ extra_note = ""
183+ if template .venv == 'isolated' :
184+ installation_note = f" Install it by running 'prich venv-install { template .id } '."
185+ else :
186+ # TODO: introduce help for shared venv installation
187+ installation_note = ""
172188 if not venv_folder .exists ():
173- failures_list .append (f"{ len (failures_list )+ 1 } . [red]Failed to find { template .venv } venv at { shorten_path (str (venv_folder ))} .[/red] Install it by running 'prich venv-install { template . id } '. " )
189+ failures_list .append (f"{ len (failures_list )+ 1 } . [red]Failed to find { template .venv } venv at { shorten_path (str (venv_folder ))} { extra_note } .[/red]{ installation_note } " )
174190 idx = 0
175191 for step in template .steps :
176192 idx += 1
@@ -196,7 +212,7 @@ def validate_templates(template_id: str, validate_file: Path, global_only: bool,
196212 output .append (f"- { template .id } [dim]({ template .source .value } ) { shorten_path (str (template_file ))} [/dim]: " )
197213 if len (failures_list ) > 0 :
198214 failures_found = True
199- output [- 1 ] += f"[red]is not valid[/red] ({ len (failures_list )} issues )"
215+ output [- 1 ] += f"[red]is not valid[/red] ({ len (failures_list )} issue { 's' if len ( failures_list ) > 1 else '' } )"
200216 failures = ' ' + '\n ' .join (failures_list )
201217 output .append (failures )
202218 output .append ("" )
@@ -206,11 +222,11 @@ def validate_templates(template_id: str, validate_file: Path, global_only: bool,
206222 failures_found = True
207223 template_source = classify_path (template_file )
208224 error_lines = ' ' + '\n ' .join ([x for x in e .message .split ('\n ' )]) + '\n '
209- output .append (f"""- { f"{ template_id } " if template_id else '' } [dim]({ template_source .value } ) { shorten_path (str (template_file ))} [/dim]: [red]is not valid[/red] { f'({ model_failures_count } issues )' if model_failures_count > 0 else '(1 issue)' } \n [red]Failed to load template{ f" { template_id } " if template_id else "" } { f" ({ template_name } )" if template_name else "" } [/red]:\n { error_lines } """ )
225+ output .append (f"""- { f"{ template_id } " if template_id else '' } [dim]({ template_source .value } ) { shorten_path (str (template_file ))} [/dim]: [red]is not valid[/red] { f'({ model_failures_count } issue { "s" if model_failures_count > 1 else "" } )' if model_failures_count > 0 else '(1 issue)' } \n [red]Failed to load template{ f" { template_id } " if template_id else "" } { f" ({ template_name } )" if template_name else "" } [/red]:\n { error_lines } """ )
210226 except Exception as e :
211227 failures_found = True
212228 template_source = classify_path (template_file )
213- output .append (f"""- { f"{ template_id } " if template_id else '' } [dim]({ template_source .value } ) { shorten_path (str (template_file ))} [/dim]: [red]is not valid[/red] (1 issue)\n [red]Failed to load template{ f" { template_id } " if template_id else "" } { f" ({ template_name } )" if template_name else "" } [/red]:\n { str (e )} """ )
229+ output .append (f"""- { f"{ template_id } " if template_id else '' } [dim]({ template_source .value } ) { shorten_path (str (template_file ))} [/dim]: [red]is not valid[/red] (1 issue)\n [red]Failed to load template{ f" { template_id } " if template_id else "" } { f" ({ template_name } )" if template_name else "" } [/red]:\n 1. { str (e )} """ )
214230 if (invalid_only and failures_found ) or not invalid_only :
215231 console_print ('\n ' .join (output ))
216232 if failures_found :
0 commit comments