Skip to content

Commit 714dffe

Browse files
committed
Add an implementation of dynamicRef that passes all the 2020-12 tests.
Is it correct? I doubt it! We shall see though. Still needs refactoring to support differences across earlier drafts / OpenAPI (and I still plan on wiping it away and starting again once doing so)
1 parent c29f44b commit 714dffe

File tree

1 file changed

+34
-7
lines changed

1 file changed

+34
-7
lines changed

referencing/_core.py

+34-7
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
from typing import TYPE_CHECKING, Any, Union
55
from urllib.parse import unquote, urldefrag, urljoin
66

7-
from pyrsistent import m, s
8-
from pyrsistent.typing import PMap, PSet
7+
from pyrsistent import m, plist, s
8+
from pyrsistent.typing import PList, PMap, PSet
99

1010
try:
1111
Mapping[str, str]
@@ -51,6 +51,9 @@ class Anchor:
5151
name: str
5252
resource: Schema
5353

54+
def resolve(self, dynamic_scope, uri) -> tuple[Schema, str]:
55+
return self.resource, uri
56+
5457

5558
@frozen
5659
class DynamicAnchor:
@@ -59,6 +62,16 @@ class DynamicAnchor:
5962
name: str
6063
resource: Schema
6164

65+
def resolve(self, dynamic_scope, uri) -> tuple[Schema, str]:
66+
last = self.resource
67+
for resource, anchors in dynamic_scope:
68+
anchor = anchors.get(self.name)
69+
if isinstance(anchor, DynamicAnchor):
70+
last = anchor.resource
71+
elif "$ref" not in resource:
72+
break
73+
return last, id_of(last) or "" # FIXME: consider when this can be None
74+
6275

6376
AnchorType = Union[Anchor, DynamicAnchor]
6477

@@ -121,8 +134,8 @@ def resource_at(self, uri: str) -> tuple[Schema, Registry]:
121134
registry = self._crawl()
122135
return registry._contents[uri][0], registry
123136

124-
def anchor_at(self, uri, name) -> AnchorType:
125-
return self._contents[uri][1][name]
137+
def anchors_at(self, uri) -> PMap[str, AnchorType]:
138+
return self._contents[uri][1]
126139

127140
def _crawl(self) -> Registry:
128141
registry = self
@@ -183,6 +196,7 @@ class Resolver:
183196

184197
_base_uri: str
185198
_registry: Registry
199+
_previous: PList[Resolver] = plist()
186200

187201
def lookup(self, ref: str) -> tuple[Schema, Resolver]:
188202
if ref.startswith("#"):
@@ -199,9 +213,13 @@ def lookup(self, ref: str) -> tuple[Schema, Resolver]:
199213
segment = segment.replace("~1", "/").replace("~0", "~")
200214
target = target[segment] # type: ignore # this can't be a bool
201215
elif fragment:
202-
target = registry.anchor_at(uri=uri, name=fragment).resource
216+
anchor = registry.anchors_at(uri=uri)[fragment]
217+
target, uri = anchor.resolve(
218+
dynamic_scope=self.dynamic_scope(),
219+
uri=uri,
220+
)
203221

204-
return target, evolve(self, base_uri=uri, registry=registry)
222+
return target, self.evolve(base_uri=uri, registry=registry)
205223

206224
def with_root(self, root) -> Resolver:
207225
maybe_relative = id_of(root)
@@ -213,7 +231,16 @@ def with_root(self, root) -> Resolver:
213231
uri=uri,
214232
resource=root,
215233
)
216-
return evolve(self, base_uri=uri, registry=registry)
234+
return self.evolve(base_uri=uri, registry=registry)
235+
236+
def evolve(self, **kwargs):
237+
previous = self._previous.cons(self._base_uri)
238+
return evolve(self, previous=previous, **kwargs)
239+
240+
def dynamic_scope(self):
241+
for uri in self._previous:
242+
resource, _ = self._registry.resource_at(uri)
243+
yield resource, self._registry.anchors_at(uri)
217244

218245

219246
SUBRESOURCE = {"items", "not"}

0 commit comments

Comments
 (0)