5
5
from urllib .parse import unquote , urldefrag , urljoin
6
6
7
7
from attrs import evolve , field
8
- from pyrsistent import m , pmap , s
9
- from pyrsistent .typing import PMap , PSet
8
+ from pyrsistent import m , plist , pmap , s
9
+ from pyrsistent .typing import PList , PMap , PSet
10
10
11
11
from referencing import exceptions
12
12
from referencing ._attrs import frozen
@@ -354,6 +354,11 @@ class Resolver(Generic[D]):
354
354
355
355
_base_uri : str = field (alias = "base_uri" )
356
356
_registry : Registry [D ] = field (alias = "registry" )
357
+ _previous : PList [URI ] = field (
358
+ default = plist (), # type: ignore[reportUnknownArgumentType]
359
+ repr = False ,
360
+ alias = "previous" ,
361
+ )
357
362
358
363
def lookup (self , ref : URI ) -> Resolved [D ]:
359
364
"""
@@ -378,24 +383,21 @@ def lookup(self, ref: URI) -> Resolved[D]:
378
383
except KeyError :
379
384
raise exceptions .Unresolvable (ref = ref ) from None
380
385
386
+ resolver = self ._evolve (registry = registry , base_uri = uri )
381
387
if fragment .startswith ("/" ):
382
- return resource .pointer (
383
- pointer = fragment ,
384
- resolver = evolve (self , registry = registry , base_uri = uri ),
385
- )
388
+ return resource .pointer (pointer = fragment , resolver = resolver )
386
389
387
390
if fragment :
388
391
try :
389
392
anchor = registry .anchor (uri , fragment )
390
393
except LookupError :
391
394
registry = registry .crawl ()
395
+ resolver = evolve (resolver , registry = registry )
392
396
anchor = registry .anchor (uri , fragment )
393
397
394
- resource = anchor .resolve ()
395
- return Resolved (
396
- contents = resource .contents ,
397
- resolver = evolve (self , registry = registry , base_uri = uri ),
398
- )
398
+ return anchor .resolve (resolver = resolver )
399
+
400
+ return Resolved (contents = resource .contents , resolver = resolver )
399
401
400
402
def in_subresource (self , subresource : Resource [D ]) -> Resolver [D ]:
401
403
"""
@@ -404,7 +406,23 @@ def in_subresource(self, subresource: Resource[D]) -> Resolver[D]:
404
406
id = subresource .id ()
405
407
if id is None :
406
408
return self
407
- return evolve (self , base_uri = urljoin (self ._base_uri , id ))
409
+ return self ._evolve (base_uri = urljoin (self ._base_uri , id ))
410
+
411
+ def dynamic_scope (self ) -> Iterable [tuple [URI , Registry [D ]]]:
412
+ """
413
+ In specs with such a notion, return the URIs in the dynamic scope.
414
+ """
415
+ for uri in self ._previous :
416
+ yield uri , self ._registry
417
+
418
+ def _evolve (self , base_uri : str , ** kwargs : Any ):
419
+ """
420
+ Evolve, appending to the dynamic scope.
421
+ """
422
+ previous = self ._previous
423
+ if self ._base_uri and base_uri != self ._base_uri :
424
+ previous = previous .cons (self ._base_uri )
425
+ return evolve (self , base_uri = base_uri , previous = previous , ** kwargs )
408
426
409
427
410
428
@frozen
@@ -416,8 +434,8 @@ class Anchor(Generic[D]):
416
434
name : str
417
435
resource : Resource [D ]
418
436
419
- def resolve (self ):
437
+ def resolve (self , resolver : Resolver [ D ] ):
420
438
"""
421
439
Return the resource for this anchor.
422
440
"""
423
- return self .resource
441
+ return Resolved ( contents = self .resource . contents , resolver = resolver )
0 commit comments