1
1
from __future__ import annotations
2
2
3
- from collections .abc import Mapping , Sequence
4
- from typing import TYPE_CHECKING , Any , Union
3
+ from collections .abc import Sequence
4
+ from typing import TYPE_CHECKING
5
5
from urllib .parse import unquote , urldefrag , urljoin
6
6
7
7
from pyrsistent import m , plist , s
8
8
from pyrsistent .typing import PList , PMap , PSet
9
9
10
- try :
11
- Mapping [str , str ]
12
- except TypeError :
13
- from typing import Mapping
14
-
15
10
16
11
class UnsupportedSubclassing (Exception ):
17
12
@classmethod
@@ -29,6 +24,8 @@ class UnidentifiedResource(Exception):
29
24
30
25
if TYPE_CHECKING :
31
26
from attrs import define , evolve , field , frozen
27
+
28
+ from referencing .typing import AnchorType , Schema , Specification
32
29
else :
33
30
from attrs import define as _define , evolve , field , frozen as _frozen
34
31
@@ -41,9 +38,6 @@ def frozen(cls):
41
38
return _frozen (cls )
42
39
43
40
44
- Schema = Union [bool , Mapping [str , Any ]]
45
-
46
-
47
41
@frozen
48
42
class Anchor :
49
43
@@ -73,7 +67,15 @@ def resolve(self, dynamic_scope, uri) -> tuple[Schema, str]:
73
67
return last , id_of (last ) or "" # FIXME: consider when this can be None
74
68
75
69
76
- AnchorType = Union [Anchor , DynamicAnchor ]
70
+ class OpaqueSpecification :
71
+ """
72
+ A non-specification `Specification` which treats resources opaquely.
73
+
74
+ In particular, they have no subresources.
75
+ """
76
+
77
+ def subresources_of (self , resource : Schema ):
78
+ return ()
77
79
78
80
79
81
@frozen
@@ -83,7 +85,8 @@ class Registry:
83
85
default = m (),
84
86
repr = lambda value : f"({ len (value )} entries)" ,
85
87
)
86
- _uncrawled : PSet [str ] = field (default = s ())
88
+ _uncrawled : PSet [str ] = s ()
89
+ _specification : Specification = OpaqueSpecification ()
87
90
88
91
def update (self , * registries : Registry ) -> Registry :
89
92
contents = (each ._contents for each in registries )
@@ -167,27 +170,17 @@ def _crawl(self) -> Registry:
167
170
resource = resource ,
168
171
),
169
172
)
170
-
171
- resources .extend ( # TODO: delay finding anchors in subresources...
172
- (uri , resource [k ]) for k in SUBRESOURCE if k in resource
173
- )
174
- resources .extend (
175
- (uri , subresource )
176
- for k in SUBRESOURCE_VALUES
177
- if k in resource
178
- for subresource in resource [k ].values ()
179
- )
180
173
resources .extend (
181
- (uri , subresource )
182
- for k in SUBRESOURCE_ITEMS
183
- if k in resource
184
- for subresource in resource [k ]
174
+ (uri , each )
175
+ for each in self ._specification .subresources_of (resource )
176
+ if each is not True and each is not False
185
177
)
186
178
return evolve (registry , uncrawled = s ())
187
179
188
- def resolver (self , root ) -> Resolver :
180
+ def resolver (self , root , specification ) -> Resolver :
189
181
uri = id_of (root ) or ""
190
182
registry = self .with_identified_resource (uri = uri , resource = root )
183
+ registry = evolve (registry , specification = specification )
191
184
return Resolver (base_uri = uri , registry = registry )
192
185
193
186
@@ -243,11 +236,6 @@ def dynamic_scope(self):
243
236
yield resource , self ._registry .anchors_at (uri )
244
237
245
238
246
- SUBRESOURCE = {"items" , "not" }
247
- SUBRESOURCE_ITEMS = {"allOf" }
248
- SUBRESOURCE_VALUES = {"$defs" , "properties" }
249
-
250
-
251
239
def id_of (resource ) -> str | None :
252
240
if resource is True or resource is False :
253
241
return None
0 commit comments