3
3
import contextlib
4
4
import json
5
5
import numbers
6
+ from functools import partial
6
7
7
8
try :
8
9
import requests
12
13
from jsonschema import _utils , _validators
13
14
from jsonschema .compat import (
14
15
Sequence , urljoin , urlsplit , urldefrag , unquote , urlopen , DefragResult ,
15
-
16
16
str_types , int_types , iteritems ,
17
17
)
18
18
from jsonschema .exceptions import ErrorTree # Backwards compatibility # noqa
@@ -109,7 +109,7 @@ def iter_errors(self, instance, _schema=None):
109
109
yield error
110
110
finally :
111
111
if scope :
112
- self .resolver .pop_scope ()
112
+ self .resolver .scopes_stack . pop ()
113
113
114
114
def descend (self , instance , schema , path = None , schema_path = None ):
115
115
for error in self .iter_errors (instance , schema ):
@@ -240,21 +240,21 @@ class RefResolver(object):
240
240
def __init__ (
241
241
self , base_uri , referrer , store = (), cache_remote = True , handlers = (),
242
242
):
243
- base_uri = urldefrag (base_uri )
244
- self .base_uri = base_uri
245
- self .resolution_scope = base_uri
246
243
# This attribute is not used, it is for backwards compatibility
247
244
self .referrer = referrer
248
245
self .cache_remote = cache_remote
249
246
self .handlers = dict (handlers )
250
247
251
- self .scopes_stack = []
248
+ self .scopes_stack = [base_uri ]
252
249
self .store = _utils .URIDict (
253
250
(id , validator .META_SCHEMA )
254
251
for id , validator in iteritems (meta_schemas )
255
252
)
256
253
self .store .update (store )
257
- self .store [base_uri .url ] = referrer
254
+ self .store [base_uri ] = referrer
255
+
256
+ self .url_cache = _utils .Cache (urljoin )
257
+ self .resolve_cache = _utils .Cache (self .resolve_from_url )
258
258
259
259
@classmethod
260
260
def from_schema (cls , schema , * args , ** kwargs ):
@@ -268,19 +268,20 @@ def from_schema(cls, schema, *args, **kwargs):
268
268
269
269
return cls (schema .get (u"id" , u"" ), schema , * args , ** kwargs )
270
270
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
- )
271
+ def push_scope (self , scope ):
272
+ self .scopes_stack .append (self .url_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 .url_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