11
11
12
12
from jsonschema import _utils , _validators
13
13
from jsonschema .compat import (
14
- Sequence , urljoin , urlsplit , urldefrag , unquote , urlopen ,
14
+ Sequence , urljoin , urlsplit , urldefrag , unquote , urlopen , DefragResult ,
15
+
15
16
str_types , int_types , iteritems ,
16
17
)
17
18
from jsonschema .exceptions import ErrorTree # Backwards compatibility # noqa
@@ -222,7 +223,7 @@ class RefResolver(object):
222
223
223
224
:argument str base_uri: URI of the referring document
224
225
:argument referrer: the actual referring document
225
- :argument dict store: a mapping from URIs to documents to cache
226
+ :argument dict store: a mapping from URIs (without fragments!) to documents to cache
226
227
:argument bool cache_remote: whether remote refs should be cached after
227
228
first resolution
228
229
:argument dict handlers: a mapping from URI schemes to functions that
@@ -233,6 +234,7 @@ class RefResolver(object):
233
234
def __init__ (
234
235
self , base_uri , referrer , store = (), cache_remote = True , handlers = (),
235
236
):
237
+ base_uri = urldefrag (base_uri )
236
238
self .base_uri = base_uri
237
239
self .resolution_scope = base_uri
238
240
# This attribute is not used, it is for backwards compatibility
@@ -241,11 +243,11 @@ def __init__(
241
243
self .handlers = dict (handlers )
242
244
243
245
self .store = _utils .URIDict (
244
- (id , validator .META_SCHEMA )
246
+ (id , validator .META_SCHEMA ) ## IDs assumed pure urls (no fragments).
245
247
for id , validator in iteritems (meta_schemas )
246
248
)
247
249
self .store .update (store )
248
- self .store [base_uri ] = referrer
250
+ self .store [base_uri . url ] = referrer
249
251
250
252
@classmethod
251
253
def from_schema (cls , schema , * args , ** kwargs ):
@@ -260,13 +262,22 @@ def from_schema(cls, schema, *args, **kwargs):
260
262
return cls (schema .get (u"id" , u"" ), schema , * args , ** kwargs )
261
263
262
264
@contextlib .contextmanager
263
- def in_scope (self , scope ):
264
- old_scope = self .resolution_scope
265
- self .resolution_scope = urljoin (old_scope , scope )
266
- try :
265
+ def in_scope (self , scope , is_defragged = False ):
266
+ if not scope :
267
267
yield
268
- finally :
269
- self .resolution_scope = old_scope
268
+ else :
269
+ old_scope = self .resolution_scope
270
+ if not is_defragged :
271
+ scope = urldefrag (scope )
272
+ self .resolution_scope = DefragResult (
273
+ urljoin (old_scope .url , scope .url , allow_fragments = False )
274
+ if scope .url else old_scope .url ,
275
+ scope .fragment
276
+ )
277
+ try :
278
+ yield
279
+ finally :
280
+ self .resolution_scope = old_scope
270
281
271
282
@contextlib .contextmanager
272
283
def resolving (self , ref ):
@@ -278,23 +289,24 @@ def resolving(self, ref):
278
289
279
290
"""
280
291
281
- full_uri = urljoin (self .resolution_scope , ref )
282
- uri , fragment = urldefrag (full_uri )
283
- if not uri :
284
- uri = self .base_uri
292
+ ref = urldefrag (ref )
285
293
286
- if uri in self .store :
287
- document = self .store [uri ]
288
- else :
294
+ url = urljoin (self .resolution_scope .url , ref .url , allow_fragments = False ) \
295
+ if ref .url else self .resolution_scope .url
296
+
297
+ try :
298
+ document = self .store [url ]
299
+ except KeyError :
289
300
try :
290
- document = self .resolve_remote (uri )
301
+ document = self .resolve_remote (url )
291
302
except Exception as exc :
292
303
raise RefResolutionError (exc )
293
304
305
+ uri = DefragResult (url , ref .fragment )
294
306
old_base_uri , self .base_uri = self .base_uri , uri
295
307
try :
296
- with self .in_scope (uri ):
297
- yield self .resolve_fragment (document , fragment )
308
+ with self .in_scope (uri , is_defragged = True ):
309
+ yield self .resolve_fragment (document , ref . fragment )
298
310
finally :
299
311
self .base_uri = old_base_uri
300
312
0 commit comments