Skip to content

Commit 6420ae7

Browse files
committed
Add resolver.in_subresource
I'm not really happy with this method existing, so I need to try to find a way to make it not need to exist. But right now it's needed, as a validation implementation which is iterating over some keyword with subschemas needs to manually track that it has entered a subschema, and then call this method to get back a resolver which takes into account the new base URI.
1 parent 52a11b6 commit 6420ae7

File tree

2 files changed

+65
-28
lines changed

2 files changed

+65
-28
lines changed

referencing/_core.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,15 @@ def lookup(self, ref: URI) -> Resolved[D]:
380380
resolver=evolve(self, registry=registry, base_uri=uri),
381381
)
382382

383+
def in_subresource(self, subresource: Resource[D]) -> Resolver[D]:
384+
"""
385+
Create a resolver for a subresource (which may have a new base URI).
386+
"""
387+
id = subresource.id()
388+
if id is None:
389+
return self
390+
return evolve(self, base_uri=urljoin(self._base_uri, id))
391+
383392

384393
@frozen
385394
class Anchor(Generic[D]):

referencing/tests/test_core.py

Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -395,12 +395,43 @@ def test_lookup_anchor_without_id(self):
395395
resolved = resolver.lookup("urn:example#foo")
396396
assert resolved.contents == 12
397397

398+
def test_lookup_unknown_reference(self):
399+
resolver = Registry().resolver()
400+
ref = "http://example.com/does/not/exist"
401+
with pytest.raises(exceptions.Unresolvable) as e:
402+
resolver.lookup(ref)
403+
assert e.value == exceptions.Unresolvable(ref=ref)
404+
405+
def test_lookup_non_existent_pointer(self):
406+
resource = Resource.opaque({"foo": {}})
407+
resolver = Registry({"http://example.com/1": resource}).resolver()
408+
ref = "http://example.com/1#/foo/bar"
409+
with pytest.raises(exceptions.Unresolvable) as e:
410+
resolver.lookup(ref)
411+
assert e.value == exceptions.PointerToNowhere(
412+
ref="/foo/bar",
413+
resource=resource,
414+
)
415+
assert str(e.value) == "'/foo/bar' does not exist within {'foo': {}}"
416+
417+
def test_lookup_non_existent_pointer_to_array_index(self):
418+
resource = Resource.opaque([1, 2, 4, 8])
419+
resolver = Registry({"http://example.com/1": resource}).resolver()
420+
ref = "http://example.com/1#/10"
421+
with pytest.raises(exceptions.Unresolvable) as e:
422+
resolver.lookup(ref)
423+
assert e.value == exceptions.PointerToNowhere(
424+
ref="/10",
425+
resource=resource,
426+
)
427+
428+
# FIXME: Ideally there'd be some way to represent the tests below in the
429+
# referencing suite, but I can't think of ways to do so yet.
430+
398431
def test_multiple_lookup(self):
399432
"""
400433
Continuing to lookup resources maintains the new base URI.
401434
"""
402-
# FIXME: Ideally there'd be some way to represent this test in the
403-
# referencing suite, but I can't think of one yet.
404435
registry = Registry(
405436
{
406437
"http://example.com/": Resource.opaque({}),
@@ -419,13 +450,6 @@ def test_multiple_lookup(self):
419450
third = second.resolver.lookup("bar")
420451
assert third.contents == {"baz": "quux"}
421452

422-
def test_lookup_unknown_reference(self):
423-
resolver = Registry().resolver()
424-
ref = "http://example.com/does/not/exist"
425-
with pytest.raises(exceptions.Unresolvable) as e:
426-
resolver.lookup(ref)
427-
assert e.value == exceptions.Unresolvable(ref=ref)
428-
429453
def test_multiple_lookup_pointer(self):
430454
registry = Registry(
431455
{
@@ -452,28 +476,32 @@ def test_multiple_lookup_anchor(self):
452476
second = first.resolver.lookup("#foo")
453477
assert second.contents == 12
454478

455-
def test_lookup_non_existent_pointer(self):
456-
resource = Resource.opaque({"foo": {}})
457-
resolver = Registry({"http://example.com/1": resource}).resolver()
458-
ref = "http://example.com/1#/foo/bar"
459-
with pytest.raises(exceptions.Unresolvable) as e:
460-
resolver.lookup(ref)
461-
assert e.value == exceptions.PointerToNowhere(
462-
ref="/foo/bar",
463-
resource=resource,
479+
def test_in_subresource(self):
480+
root = ID_AND_CHILDREN.create_resource(
481+
{
482+
"ID": "http://example.com/",
483+
"children": [
484+
{
485+
"ID": "child/",
486+
"children": [{"ID": "grandchild"}],
487+
},
488+
],
489+
},
464490
)
465-
assert str(e.value) == "'/foo/bar' does not exist within {'foo': {}}"
491+
registry = Registry().with_resource(root.id(), root)
466492

467-
def test_lookup_non_existent_pointer_to_array_index(self):
468-
resource = Resource.opaque([1, 2, 4, 8])
469-
resolver = Registry({"http://example.com/1": resource}).resolver()
470-
ref = "http://example.com/1#/10"
471-
with pytest.raises(exceptions.Unresolvable) as e:
472-
resolver.lookup(ref)
473-
assert e.value == exceptions.PointerToNowhere(
474-
ref="/10",
475-
resource=resource,
493+
resolver = registry.resolver()
494+
first = resolver.lookup("http://example.com/")
495+
assert first.contents == root.contents
496+
497+
with pytest.raises(exceptions.Unresolvable):
498+
first.resolver.lookup("grandchild")
499+
500+
sub = first.resolver.in_subresource(
501+
ID_AND_CHILDREN.create_resource(first.contents["children"][0]),
476502
)
503+
second = sub.lookup("grandchild")
504+
assert second.contents == {"ID": "grandchild"}
477505

478506

479507
class TestSpecification:

0 commit comments

Comments
 (0)