@@ -46,15 +46,21 @@ def from_resource(
46
46
def id (self ):
47
47
return self ._specification .id_of (self .resource )
48
48
49
- def anchors (self ):
49
+ def anchors (self ) -> list [AnchorType ]:
50
+ if isinstance (self .resource , bool ):
51
+ return []
50
52
return self ._specification .anchors_in (self .resource )
51
53
52
- def subresources (self ):
53
- for each in self ._specification .subresources_of (self .resource ):
54
- yield IdentifiedResource .from_resource (
54
+ def subresources (self ) -> Iterable [IdentifiedResource ]:
55
+ subresources = self ._specification .subresources_of (self .resource ) # type: ignore # FIXME: missing test # noqa: E501
56
+ return (
57
+ IdentifiedResource .from_resource (
55
58
resource = each ,
56
59
default_specification = self ._specification ,
57
60
)
61
+ for each in subresources
62
+ if each is not True and each is not False
63
+ )
58
64
59
65
60
66
@frozen
@@ -77,17 +83,17 @@ class Specification:
77
83
78
84
id_of : Callable [[Schema ], str | None ]
79
85
subresources_of : Callable [[ObjectSchema ], Iterable [Schema ]]
80
- _anchors_in : Callable [[ObjectSchema , Specification ], Iterable [AnchorType ]]
86
+ _anchors_in : Callable [[ObjectSchema , Specification ], list [AnchorType ]]
81
87
82
- def anchors_in (self , resource : ObjectSchema ) -> Iterable [AnchorType ]:
88
+ def anchors_in (self , resource : ObjectSchema ) -> list [AnchorType ]:
83
89
return self ._anchors_in (resource , self )
84
90
85
91
86
92
#: A 'null' specification, where resources are opaque
87
93
#: (e.g. have no subresources or IDs).
88
94
OPAQUE_SPECIFICATION = Specification (
89
95
id_of = lambda resource : None ,
90
- anchors_in = lambda resource , specification : () ,
96
+ anchors_in = lambda resource , specification : [] ,
91
97
subresources_of = lambda resource : (),
92
98
)
93
99
@@ -141,57 +147,54 @@ def with_identified_resources(
141
147
self ,
142
148
pairs : Iterable [tuple [str , IdentifiedResource ]],
143
149
) -> Registry :
144
- uncrawled = self ._uncrawled
145
- contents = self ._contents
150
+ uncrawled = self ._uncrawled . evolver ()
151
+ contents = self ._contents . evolver ()
146
152
for uri , resource in pairs :
147
- anchors : PMap [str , AnchorType ] = m ()
148
- contents = contents .set (uri , (resource , anchors ))
149
- id = resource .id ()
150
- if id is not None :
151
- contents = contents .set (id , (resource , anchors ))
152
-
153
- uncrawled = uncrawled .add (uri )
154
- return evolve (self , contents = contents , uncrawled = uncrawled )
153
+ contents [uri ] = resource , m ()
154
+ uncrawled .add (uri )
155
+ return evolve (
156
+ self ,
157
+ contents = contents .persistent (),
158
+ uncrawled = uncrawled .persistent (),
159
+ )
155
160
156
- def with_anchors (
161
+ def _with_anchors (
157
162
self ,
158
163
uri : str ,
159
164
anchors : Iterable [AnchorType ],
160
165
) -> Registry :
161
166
assert uri .endswith ("#" ) or "#" not in uri , uri
162
167
resource , old = self ._contents [uri ]
163
168
new = old .update ({anchor .name : anchor for anchor in anchors })
164
- contents = self ._contents .set (uri , (resource , new ))
165
- return evolve (self , contents = contents )
169
+ return evolve (self , contents = self ._contents .set (uri , (resource , new )))
166
170
167
- def resource_at (self , uri : str ) -> tuple [IdentifiedResource , Registry ]:
171
+ def resource_at (
172
+ self , uri : str
173
+ ) -> tuple [IdentifiedResource , PMap [str , AnchorType ], Registry ]:
168
174
at_uri = self ._contents .get (uri )
169
- if at_uri is not None and at_uri [1 ]:
170
- registry = self
171
- else :
175
+ if at_uri is None or uri in self ._uncrawled :
172
176
registry = self ._crawl ()
173
- return registry ._contents [uri ][0 ], registry
174
-
175
- def anchors_at (self , uri : str ) -> PMap [str , AnchorType ]:
176
- return self ._contents [uri ][1 ]
177
+ return * registry ._contents [uri ], registry
178
+ return * at_uri , self
177
179
178
180
def _crawl (self ) -> Registry :
179
181
registry = self
180
182
resources = [(uri , self ._contents [uri ][0 ]) for uri in self ._uncrawled ]
181
183
while resources :
182
184
base_uri , resource = resources .pop ()
183
- if resource . resource is True or resource .resource is False :
184
- continue
185
-
186
- uri = urljoin ( base_uri , resource . id () or "" )
187
- if uri != base_uri :
185
+ id = resource .id ()
186
+ if id is None :
187
+ uri = base_uri
188
+ else :
189
+ uri = urljoin ( base_uri , id )
188
190
registry = registry .with_identified_resource (
189
191
uri = uri ,
190
192
resource = resource ,
191
193
)
192
194
193
195
anchors = resource .anchors ()
194
- registry = registry .with_anchors (uri = uri , anchors = anchors )
196
+ if anchors :
197
+ registry = registry ._with_anchors (uri , anchors )
195
198
196
199
resources .extend ((uri , each ) for each in resource .subresources ())
197
200
return evolve (registry , uncrawled = s ())
@@ -221,7 +224,7 @@ def lookup(self, ref: str) -> tuple[Schema, Resolver]:
221
224
else :
222
225
uri , fragment = urldefrag (urljoin (self ._base_uri , ref ))
223
226
224
- resource , registry = self ._registry .resource_at (uri )
227
+ resource , anchors , registry = self ._registry .resource_at (uri )
225
228
base_uri = uri
226
229
target = resource .resource
227
230
@@ -240,19 +243,17 @@ def lookup(self, ref: str) -> tuple[Schema, Resolver]:
240
243
if id is not None :
241
244
base_uri = urljoin (base_uri , id ).rstrip ("#" )
242
245
elif fragment :
243
- anchor = registry .anchors_at (uri = uri )[fragment ]
244
- resource , uri = anchor .resolve (resolver = self , uri = uri )
246
+ resource , uri = anchors [fragment ].resolve (resolver = self , uri = uri )
245
247
target = resource .resource
246
248
247
249
id = resource .id ()
248
250
if id is not None :
249
251
base_uri = urljoin (self ._base_uri , id ).rstrip ("#" )
250
252
else :
251
- target = resource .resource
252
253
id = resource .id ()
253
254
if id is not None :
254
255
base_uri = urljoin (self ._base_uri , id ).rstrip ("#" )
255
- return target , self .evolve (base_uri = base_uri , registry = registry )
256
+ return target , self ._evolve (base_uri = base_uri , registry = registry )
256
257
257
258
def with_root (
258
259
self ,
@@ -271,14 +272,13 @@ def with_root(
271
272
specification = specification ,
272
273
),
273
274
)
274
- return self .evolve (base_uri = uri , registry = registry )
275
-
276
- def evolve (self , ** kwargs ):
277
- previous = self ._previous .cons (self ._base_uri )
278
- return evolve (self , previous = previous , ** kwargs )
275
+ return self ._evolve (base_uri = uri , registry = registry )
279
276
280
277
def dynamic_scope (self ):
281
278
for uri in self ._previous :
282
- resource , _ = self ._registry .resource_at (uri )
283
- anchors = self ._registry .anchors_at (uri )
279
+ resource , anchors , _ = self ._registry .resource_at (uri )
284
280
yield uri , resource , anchors
281
+
282
+ def _evolve (self , ** kwargs ):
283
+ previous = self ._previous .cons (self ._base_uri )
284
+ return evolve (self , previous = previous , ** kwargs )
0 commit comments