1
1
from __future__ import annotations
2
2
3
- from collections .abc import Sequence
3
+ from collections .abc import Iterable , Sequence
4
4
from urllib .parse import unquote , urldefrag , urljoin
5
5
6
6
from attrs import evolve , field
7
7
from pyrsistent import m , plist , s
8
8
from pyrsistent .typing import PList , PMap , PSet
9
9
10
10
from referencing ._attrs import define , frozen
11
- from referencing .jsonschema import DynamicAnchor , id_of
12
11
from referencing .typing import Anchor as AnchorType , Schema , Specification
13
12
14
13
@@ -19,11 +18,10 @@ class UnidentifiedResource(Exception):
19
18
@frozen
20
19
class Anchor :
21
20
22
- uri : str
23
21
name : str
24
22
resource : Schema
25
23
26
- def resolve (self , dynamic_scope , uri ) -> tuple [Schema , str ]:
24
+ def resolve (self , resolver , uri ) -> tuple [Schema , str ]:
27
25
return self .resource , uri
28
26
29
27
@@ -34,7 +32,15 @@ class OpaqueSpecification:
34
32
In particular, they have no subresources.
35
33
"""
36
34
37
- def subresources_of (self , resource : Schema ):
35
+ def id_of (self , resource ):
36
+ if resource is True or resource is False :
37
+ return
38
+ return resource .get ("$id" ) # REMOVEME
39
+
40
+ def anchors_in (self , resource ):
41
+ return ()
42
+
43
+ def subresources_of (self , resource ):
38
44
return ()
39
45
40
46
@@ -45,7 +51,7 @@ class Registry:
45
51
default = m (),
46
52
repr = lambda value : f"({ len (value )} entries)" ,
47
53
)
48
- _uncrawled : PSet [str ] = s ( )
54
+ _uncrawled : PSet [str ] = field ( default = s (), repr = False )
49
55
_specification : Specification = OpaqueSpecification ()
50
56
51
57
def update (self , * registries : Registry ) -> Registry :
@@ -58,7 +64,7 @@ def update(self, *registries: Registry) -> Registry:
58
64
)
59
65
60
66
def with_resource (self , resource ) -> Registry :
61
- uri = id_of (resource )
67
+ uri = self . _specification . id_of (resource )
62
68
if uri is None :
63
69
raise UnidentifiedResource (resource )
64
70
return self .with_identified_resource (uri = uri , resource = resource )
@@ -77,17 +83,23 @@ def with_resources(self, pairs) -> Registry:
77
83
), (uri , self ._contents [uri ], resource )
78
84
contents = contents .set (uri , (resource , m ()))
79
85
80
- id = id_of (resource )
86
+ id = self . _specification . id_of (resource )
81
87
if id is not None :
82
88
contents = contents .set (id , (resource , m ()))
83
89
84
90
uncrawled = uncrawled .add (uri )
85
91
return evolve (self , contents = contents , uncrawled = uncrawled )
86
92
87
- def with_anchor (self , anchor : AnchorType ) -> Registry :
88
- resource , anchors = self ._contents [anchor .uri ]
89
- new = resource , anchors .set (anchor .name , anchor )
90
- return evolve (self , contents = self ._contents .set (anchor .uri , new ))
93
+ def with_anchors (
94
+ self ,
95
+ uri : str ,
96
+ anchors : Iterable [AnchorType ],
97
+ ) -> Registry :
98
+ assert "#" not in uri , uri
99
+ resource , old = self ._contents [uri ]
100
+ new = old .update ({anchor .name : anchor for anchor in anchors })
101
+ contents = self ._contents .set (uri , (resource , new ))
102
+ return evolve (self , contents = contents )
91
103
92
104
def resource_at (self , uri : str ) -> tuple [Schema , Registry ]:
93
105
at_uri = self ._contents .get (uri )
@@ -108,28 +120,16 @@ def _crawl(self) -> Registry:
108
120
if resource is True or resource is False :
109
121
continue
110
122
111
- uri = urljoin (base_uri , resource . get ( "$id" , "" ) )
123
+ uri = urljoin (base_uri , self . _specification . id_of ( resource ) or "" )
112
124
if uri != base_uri :
113
125
registry = registry .with_identified_resource (
114
126
uri = uri ,
115
127
resource = resource ,
116
128
)
117
129
118
- anchor = resource .get ("$anchor" )
119
- if anchor is not None :
120
- registry = registry .with_anchor (
121
- Anchor (uri = uri , name = anchor , resource = resource ),
122
- )
130
+ anchors = self ._specification .anchors_in (resource )
131
+ registry = registry .with_anchors (uri = uri , anchors = anchors )
123
132
124
- dynamic_anchor = resource .get ("$dynamicAnchor" )
125
- if dynamic_anchor is not None :
126
- registry = registry .with_anchor (
127
- DynamicAnchor (
128
- uri = uri ,
129
- name = dynamic_anchor ,
130
- resource = resource ,
131
- ),
132
- )
133
133
resources .extend (
134
134
(uri , each )
135
135
for each in self ._specification .subresources_of (resource )
@@ -138,7 +138,7 @@ def _crawl(self) -> Registry:
138
138
return evolve (registry , uncrawled = s ())
139
139
140
140
def resolver (self , root , specification ) -> Resolver :
141
- uri = id_of (root ) or ""
141
+ uri = self . _specification . id_of (root ) or ""
142
142
registry = self .with_identified_resource (uri = uri , resource = root )
143
143
registry = evolve (registry , specification = specification )
144
144
return Resolver (base_uri = uri , registry = registry )
@@ -167,15 +167,12 @@ def lookup(self, ref: str) -> tuple[Schema, Resolver]:
167
167
target = target [segment ] # type: ignore # this can't be a bool
168
168
elif fragment :
169
169
anchor = registry .anchors_at (uri = uri )[fragment ]
170
- target , uri = anchor .resolve (
171
- dynamic_scope = self .dynamic_scope (),
172
- uri = uri ,
173
- )
170
+ target , uri = anchor .resolve (resolver = self , uri = uri )
174
171
175
172
return target , self .evolve (base_uri = uri , registry = registry )
176
173
177
174
def with_root (self , root ) -> Resolver :
178
- maybe_relative = id_of (root )
175
+ maybe_relative = self . _registry . _specification . id_of (root )
179
176
if maybe_relative is None :
180
177
return self
181
178
0 commit comments