11
11
12
12
from jsonschema import _utils , _validators
13
13
from jsonschema .compat import (
14
- Sequence , urljoin , urlsplit , urldefrag , unquote , urlopen , DefragResult ,
15
-
14
+ Sequence , urljoin , urlsplit , urldefrag , unquote , urlopen ,
16
15
str_types , int_types , iteritems ,
17
16
)
18
17
from jsonschema .exceptions import ErrorTree # Backwards compatibility # noqa
@@ -109,7 +108,7 @@ def iter_errors(self, instance, _schema=None):
109
108
yield error
110
109
finally :
111
110
if scope :
112
- self .resolver .pop_scope ()
111
+ self .resolver .scopes_stack . pop ()
113
112
114
113
def descend (self , instance , schema , path = None , schema_path = None ):
115
114
for error in self .iter_errors (instance , schema ):
@@ -240,21 +239,21 @@ class RefResolver(object):
240
239
def __init__ (
241
240
self , base_uri , referrer , store = (), cache_remote = True , handlers = (),
242
241
):
243
- base_uri = urldefrag (base_uri )
244
- self .base_uri = base_uri
245
- self .resolution_scope = base_uri
246
242
# This attribute is not used, it is for backwards compatibility
247
243
self .referrer = referrer
248
244
self .cache_remote = cache_remote
249
245
self .handlers = dict (handlers )
250
246
251
- self .scopes_stack = []
247
+ self .scopes_stack = [base_uri ]
252
248
self .store = _utils .URIDict (
253
249
(id , validator .META_SCHEMA )
254
250
for id , validator in iteritems (meta_schemas )
255
251
)
256
252
self .store .update (store )
257
- self .store [base_uri .url ] = referrer
253
+ self .store [base_uri ] = referrer
254
+
255
+ self .urljoin_cache = _utils .Cache (urljoin )
256
+ self .resolve_cache = _utils .Cache (self .resolve_from_url )
258
257
259
258
@classmethod
260
259
def from_schema (cls , schema , * args , ** kwargs ):
@@ -268,19 +267,21 @@ def from_schema(cls, schema, *args, **kwargs):
268
267
269
268
return cls (schema .get (u"id" , u"" ), schema , * args , ** kwargs )
270
269
271
- def push_scope (self , scope , is_defragged = False ):
272
- old_scope = self .resolution_scope
273
- self .scopes_stack .append (old_scope )
274
- if not is_defragged :
275
- scope = urldefrag (scope )
276
- self .resolution_scope = DefragResult (
277
- urljoin (old_scope .url , scope .url , allow_fragments = False )
278
- if scope .url else old_scope .url ,
279
- scope .fragment
280
- )
270
+ def push_scope (self , scope ):
271
+ self .scopes_stack .append (
272
+ self .urljoin_cache (self .resolution_scope , scope ))
273
+
274
+ @property
275
+ def resolution_scope (self ):
276
+ return self .scopes_stack [- 1 ]
281
277
282
- def pop_scope (self ):
283
- self .resolution_scope = self .scopes_stack .pop ()
278
+ @contextlib .contextmanager
279
+ def in_scope (self , scope ):
280
+ self .push_scope (scope )
281
+ try :
282
+ yield
283
+ finally :
284
+ self .scopes_stack .pop ()
284
285
285
286
@contextlib .contextmanager
286
287
def resolving (self , ref ):
@@ -291,33 +292,25 @@ def resolving(self, ref):
291
292
:argument str ref: reference to resolve
292
293
293
294
"""
295
+ url = self .urljoin_cache (self .resolution_scope , ref )
294
296
295
- ref = urldefrag (ref )
296
-
297
- if ref .url :
298
- url = urljoin (
299
- self .resolution_scope .url ,
300
- ref .url ,
301
- allow_fragments = False )
302
- else :
303
- url = self .resolution_scope .url
297
+ self .push_scope (url )
298
+ try :
299
+ yield self .resolve_cache (url )
300
+ finally :
301
+ self .scopes_stack .pop ()
304
302
303
+ def resolve_from_url (self , url ):
304
+ ref = urldefrag (url )
305
305
try :
306
- document = self .store [url ]
306
+ document = self .store [ref . url ]
307
307
except KeyError :
308
308
try :
309
- document = self .resolve_remote (url )
309
+ document = self .resolve_remote (ref . url )
310
310
except Exception as exc :
311
311
raise RefResolutionError (exc )
312
312
313
- uri = DefragResult (url , ref .fragment )
314
- old_base_uri , self .base_uri = self .base_uri , uri
315
- self .push_scope (uri , is_defragged = True )
316
- try :
317
- yield self .resolve_fragment (document , ref .fragment )
318
- finally :
319
- self .pop_scope ()
320
- self .base_uri = old_base_uri
313
+ return self .resolve_fragment (document , ref .fragment )
321
314
322
315
def resolve_fragment (self , document , fragment ):
323
316
"""
0 commit comments