11"""OpenAPI spec validator validation validators module."""
22import logging
33import string
4+ import warnings
45from typing import Any
5- from typing import Callable
6- from typing import Hashable
76from typing import Iterator
87from typing import List
9- from typing import Mapping
108from typing import Optional
119from typing import Type
1210
1311from jsonschema ._format import FormatChecker
1412from jsonschema .exceptions import ValidationError
1513from jsonschema .protocols import Validator
16- from jsonschema .validators import RefResolver
17- from jsonschema_spec .accessors import SpecAccessor
18- from jsonschema_spec .paths import Spec
14+ from jsonschema_spec .handlers import default_handlers
15+ from jsonschema_spec .paths import SchemaPath
16+ from jsonschema_spec .typing import ResolverHandlers
17+ from jsonschema_spec .typing import Schema
1918
2019from openapi_spec_validator .validation .decorators import ValidationErrorWrapper
2120from openapi_spec_validator .validation .exceptions import (
3534wraps_errors = ValidationErrorWrapper (OpenAPIValidationError )
3635
3736
38- def is_ref (spec : Any ) -> bool :
39- return isinstance (spec , dict ) and "$ref" in spec
40-
41-
4237class SpecValidator :
43-
4438 OPERATIONS = [
4539 "get" ,
4640 "put" ,
@@ -57,7 +51,7 @@ def __init__(
5751 schema_validator : Validator ,
5852 value_validator_class : Type [Validator ],
5953 value_validator_format_checker : FormatChecker ,
60- resolver_handlers : Optional [ Mapping [ str , Callable [[ str ], Any ]]] = None ,
54+ resolver_handlers : ResolverHandlers = default_handlers ,
6155 ):
6256 self .schema_validator = schema_validator
6357 self .value_validator_class = value_validator_class
@@ -66,30 +60,48 @@ def __init__(
6660
6761 self .operation_ids_registry : Optional [List [str ]] = None
6862 self .schema_ids_registry : Optional [List [int ]] = None
69- self .resolver = None
7063
7164 def validate (
72- self , instance : Mapping [Hashable , Any ], spec_url : str = ""
65+ self ,
66+ schema : Schema ,
67+ base_uri : str = "" ,
68+ spec_url : Optional [str ] = None ,
7369 ) -> None :
74- for err in self .iter_errors (instance , spec_url = spec_url ):
70+ for err in self .iter_errors (
71+ schema ,
72+ base_uri = base_uri ,
73+ spec_url = spec_url ,
74+ ):
7575 raise err
7676
77- def is_valid (self , instance : Mapping [ Hashable , Any ] ) -> bool :
78- error = next (self .iter_errors (instance ), None )
77+ def is_valid (self , schema : Schema ) -> bool :
78+ error = next (self .iter_errors (schema ), None )
7979 return error is None
8080
8181 @wraps_errors
8282 def iter_errors (
83- self , instance : Mapping [Hashable , Any ], spec_url : str = ""
83+ self ,
84+ schema : Schema ,
85+ base_uri : str = "" ,
86+ spec_url : Optional [str ] = None ,
8487 ) -> Iterator [ValidationError ]:
88+ if spec_url is not None :
89+ warnings .warn (
90+ "spec_url parameter is deprecated. " "Use base_uri instead." ,
91+ DeprecationWarning ,
92+ )
93+ base_uri = spec_url
94+
8595 self .operation_ids_registry = []
8696 self .schema_ids_registry = []
87- self .resolver = self ._get_resolver (spec_url , instance )
8897
89- yield from self .schema_validator .iter_errors (instance )
98+ yield from self .schema_validator .iter_errors (schema )
9099
91- accessor = SpecAccessor (instance , self .resolver )
92- spec = Spec (accessor )
100+ spec = SchemaPath .from_dict (
101+ schema ,
102+ base_uri = base_uri ,
103+ handlers = self .resolver_handlers ,
104+ )
93105 if "paths" in spec :
94106 paths = spec / "paths"
95107 yield from self ._iter_paths_errors (paths )
@@ -98,17 +110,14 @@ def iter_errors(
98110 components = spec / "components"
99111 yield from self ._iter_components_errors (components )
100112
101- def _get_resolver (
102- self , base_uri : str , referrer : Mapping [Hashable , Any ]
103- ) -> RefResolver :
104- return RefResolver (base_uri , referrer , handlers = self .resolver_handlers )
105-
106- def _iter_paths_errors (self , paths : Spec ) -> Iterator [ValidationError ]:
113+ def _iter_paths_errors (
114+ self , paths : SchemaPath
115+ ) -> Iterator [ValidationError ]:
107116 for url , path_item in paths .items ():
108117 yield from self ._iter_path_errors (url , path_item )
109118
110119 def _iter_path_errors (
111- self , url : str , path_item : Spec
120+ self , url : str , path_item : SchemaPath
112121 ) -> Iterator [ValidationError ]:
113122 parameters = None
114123 if "parameters" in path_item :
@@ -127,8 +136,8 @@ def _iter_operation_errors(
127136 self ,
128137 url : str ,
129138 name : str ,
130- operation : Spec ,
131- path_parameters : Optional [Spec ],
139+ operation : SchemaPath ,
140+ path_parameters : Optional [SchemaPath ],
132141 ) -> Iterator [ValidationError ]:
133142 assert self .operation_ids_registry is not None
134143
@@ -168,13 +177,13 @@ def _iter_operation_errors(
168177 return
169178
170179 def _iter_responses_errors (
171- self , responses : Spec
180+ self , responses : SchemaPath
172181 ) -> Iterator [ValidationError ]:
173182 for response_code , response in responses .items ():
174183 yield from self ._iter_response_errors (response_code , response )
175184
176185 def _iter_response_errors (
177- self , response_code : str , response : Spec
186+ self , response_code : str , response : SchemaPath
178187 ) -> Iterator [ValidationError ]:
179188 # openapi 2
180189 if "schema" in response :
@@ -185,18 +194,20 @@ def _iter_response_errors(
185194 content = response / "content"
186195 yield from self ._iter_content_errors (content )
187196
188- def _iter_content_errors (self , content : Spec ) -> Iterator [ValidationError ]:
197+ def _iter_content_errors (
198+ self , content : SchemaPath
199+ ) -> Iterator [ValidationError ]:
189200 for mimetype , media_type in content .items ():
190201 yield from self ._iter_media_type_errors (mimetype , media_type )
191202
192203 def _iter_media_type_errors (
193- self , mimetype : str , media_type : Spec
204+ self , mimetype : str , media_type : SchemaPath
194205 ) -> Iterator [ValidationError ]:
195206 if "schema" in media_type :
196207 schema = media_type / "schema"
197208 yield from self ._iter_schema_errors (schema )
198209
199- def _get_path_param_names (self , params : Spec ) -> Iterator [str ]:
210+ def _get_path_param_names (self , params : SchemaPath ) -> Iterator [str ]:
200211 for param in params :
201212 if param ["in" ] == "path" :
202213 yield param ["name" ]
@@ -207,7 +218,7 @@ def _get_path_params_from_url(self, url: str) -> Iterator[str]:
207218 return filter (None , path_params )
208219
209220 def _iter_parameters_errors (
210- self , parameters : Spec
221+ self , parameters : SchemaPath
211222 ) -> Iterator [ValidationError ]:
212223 seen = set ()
213224 for parameter in parameters :
@@ -221,7 +232,7 @@ def _iter_parameters_errors(
221232 seen .add (key )
222233
223234 def _iter_parameter_errors (
224- self , parameter : Spec
235+ self , parameter : SchemaPath
225236 ) -> Iterator [ValidationError ]:
226237 if "schema" in parameter :
227238 schema = parameter / "schema"
@@ -234,18 +245,18 @@ def _iter_parameter_errors(
234245 yield from self ._iter_value_errors (parameter , default )
235246
236247 def _iter_value_errors (
237- self , schema : Spec , value : Any
248+ self , schema : SchemaPath , value : Any
238249 ) -> Iterator [ValidationError ]:
239- with schema .open () as content :
250+ with schema .resolve () as resolved :
240251 validator = self .value_validator_class (
241- content ,
242- resolver = self .resolver ,
252+ resolved . contents ,
253+ _resolver = resolved .resolver ,
243254 format_checker = self .value_validator_format_checker ,
244255 )
245256 yield from validator .iter_errors (value )
246257
247258 def _iter_schema_errors (
248- self , schema : Spec , require_properties : bool = True
259+ self , schema : SchemaPath , require_properties : bool = True
249260 ) -> Iterator [ValidationError ]:
250261 if not hasattr (schema .content (), "__getitem__" ):
251262 return
@@ -329,11 +340,13 @@ def _iter_schema_errors(
329340 yield from self ._iter_value_errors (schema , default )
330341
331342 def _iter_components_errors (
332- self , components : Spec
343+ self , components : SchemaPath
333344 ) -> Iterator [ValidationError ]:
334345 schemas = components .get ("schemas" , {})
335346 yield from self ._iter_schemas_errors (schemas )
336347
337- def _iter_schemas_errors (self , schemas : Spec ) -> Iterator [ValidationError ]:
348+ def _iter_schemas_errors (
349+ self , schemas : SchemaPath
350+ ) -> Iterator [ValidationError ]:
338351 for _ , schema in schemas .items ():
339352 yield from self ._iter_schema_errors (schema )
0 commit comments