11import logging
2+ import os
23import sys
34from argparse import ArgumentParser
45from collections .abc import Sequence
910from openapi_spec_validator import __version__
1011from openapi_spec_validator .readers import read_from_filename
1112from openapi_spec_validator .readers import read_from_stdin
13+ from openapi_spec_validator .shortcuts import get_validator_cls
1214from openapi_spec_validator .shortcuts import validate
1315from openapi_spec_validator .validation import OpenAPIV2SpecValidator
1416from openapi_spec_validator .validation import OpenAPIV30SpecValidator
@@ -30,27 +32,42 @@ def print_error(filename: str, exc: Exception) -> None:
3032
3133
3234def print_validationerror (
33- filename : str , exc : ValidationError , errors : str = "best-match"
35+ filename : str ,
36+ exc : ValidationError ,
37+ subschema_errors : str = "best-match" ,
38+ index : int | None = None ,
3439) -> None :
35- print (f"{ filename } : Validation Error: { exc } " )
40+ if index is None :
41+ print (f"{ filename } : Validation Error: { exc } " )
42+ else :
43+ print (f"{ filename } : Validation Error: [{ index } ] { exc } " )
3644 if exc .cause :
3745 print ("\n # Cause\n " )
3846 print (exc .cause )
3947 if not exc .context :
4048 return
41- if errors == "all" :
49+ if subschema_errors == "all" :
4250 print ("\n \n # Due to one of those errors\n " )
4351 print ("\n \n \n " .join ("## " + str (e ) for e in exc .context ))
44- elif errors == "best-match" :
52+ elif subschema_errors == "best-match" :
4553 print ("\n \n # Probably due to this subschema error\n " )
4654 print ("## " + str (best_match (exc .context )))
4755 if len (exc .context ) > 1 :
4856 print (
4957 f"\n ({ len (exc .context ) - 1 } more subschemas errors," ,
50- "use --errors=all to see them.)" ,
58+ "use --subschema- errors=all to see them.)" ,
5159 )
5260
5361
62+ def should_warn_deprecated () -> bool :
63+ return os .getenv ("OPENAPI_SPEC_VALIDATOR_WARN_DEPRECATED" , "1" ) != "0"
64+
65+
66+ def warn_deprecated (message : str ) -> None :
67+ if should_warn_deprecated ():
68+ print (f"DeprecationWarning: { message } " , file = sys .stderr )
69+
70+
5471def main (args : Sequence [str ] | None = None ) -> None :
5572 parser = ArgumentParser (prog = "openapi-spec-validator" )
5673 parser .add_argument (
@@ -59,12 +76,27 @@ def main(args: Sequence[str] | None = None) -> None:
5976 help = "Validate specified file(s)." ,
6077 )
6178 parser .add_argument (
62- "--errors" ,
79+ "--subschema- errors" ,
6380 choices = ("best-match" , "all" ),
64- default = "best-match" ,
65- help = """Control error reporting . Defaults to "best-match", """
81+ default = None ,
82+ help = """Control subschema error details . Defaults to "best-match", """
6683 """use "all" to get all subschema errors.""" ,
6784 )
85+ parser .add_argument (
86+ "--validation-errors" ,
87+ choices = ("first" , "all" ),
88+ default = "first" ,
89+ help = """Control validation errors count. Defaults to "first", """
90+ """use "all" to get all validation errors.""" ,
91+ )
92+ parser .add_argument (
93+ "--errors" ,
94+ "--error" ,
95+ dest = "deprecated_subschema_errors" ,
96+ choices = ("best-match" , "all" ),
97+ default = None ,
98+ help = "Deprecated alias for --subschema-errors." ,
99+ )
68100 parser .add_argument (
69101 "--schema" ,
70102 type = str ,
@@ -80,6 +112,22 @@ def main(args: Sequence[str] | None = None) -> None:
80112 )
81113 args_parsed = parser .parse_args (args )
82114
115+ subschema_errors = args_parsed .subschema_errors
116+ if args_parsed .deprecated_subschema_errors is not None :
117+ if args_parsed .subschema_errors is None :
118+ subschema_errors = args_parsed .deprecated_subschema_errors
119+ warn_deprecated (
120+ "--errors/--error is deprecated. "
121+ "Use --subschema-errors instead."
122+ )
123+ else :
124+ warn_deprecated (
125+ "--errors/--error is deprecated and ignored when "
126+ "--subschema-errors is provided."
127+ )
128+ if subschema_errors is None :
129+ subschema_errors = "best-match"
130+
83131 for filename in args_parsed .file :
84132 # choose source
85133 reader = read_from_filename
@@ -108,9 +156,27 @@ def main(args: Sequence[str] | None = None) -> None:
108156
109157 # validate
110158 try :
159+ if args_parsed .validation_errors == "all" :
160+ if validator_cls is None :
161+ validator_cls = get_validator_cls (spec )
162+ validator = validator_cls (spec , base_uri = base_uri )
163+ errors = list (validator .iter_errors ())
164+ if errors :
165+ for idx , exc in enumerate (errors , start = 1 ):
166+ print_validationerror (
167+ filename ,
168+ exc ,
169+ subschema_errors ,
170+ index = idx ,
171+ )
172+ print (f"{ filename } : { len (errors )} validation errors found" )
173+ sys .exit (1 )
174+ print_ok (filename )
175+ continue
176+
111177 validate (spec , base_uri = base_uri , cls = validator_cls )
112178 except ValidationError as exc :
113- print_validationerror (filename , exc , args_parsed . errors )
179+ print_validationerror (filename , exc , subschema_errors )
114180 sys .exit (1 )
115181 except Exception as exc :
116182 print_error (filename , exc )
0 commit comments