Skip to content

Commit 4614520

Browse files
committed
Try to be more helpful when someone forgets a slash in JSON pointers.
Refs: python-jsonschema/jsonschema#1070
1 parent a4a9318 commit 4614520

File tree

4 files changed

+52
-0
lines changed

4 files changed

+52
-0
lines changed

docs/spelling-wordlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ autodetecting
33
boolean
44
changelog
55
deduplication
6+
dereferenced
67
deserialized
78
discoverability
89
filesystem

referencing/_core.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,16 @@ def anchor(self, uri: URI, name: str):
359359
value = registry._anchors.get((uri, name))
360360
if value is not None:
361361
return Retrieved(value=value, registry=registry)
362+
if "/" in name:
363+
raise exceptions.InvalidAnchor(
364+
ref=uri,
365+
resource=self[uri],
366+
anchor=name,
367+
suggestion=(
368+
f"You may have intended to use '#/{name}'. The slash is "
369+
"required *before each* segment of a JSON Pointer."
370+
),
371+
)
362372
raise exceptions.NoSuchAnchor(ref=uri, resource=self[uri], anchor=name)
363373

364374
def contents(self, uri: URI) -> D:

referencing/exceptions.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,27 @@ def __str__(self):
107107
return (
108108
f"{self.anchor!r} does not exist within {self.resource.contents!r}"
109109
)
110+
111+
112+
@frozen
113+
class InvalidAnchor(Unresolvable):
114+
"""
115+
An anchor which could never exist in a resource was dereferenced.
116+
117+
It is somehow syntactically invalid.
118+
"""
119+
120+
resource: Resource[Any]
121+
anchor: str
122+
_suggestion: str | None = attrs.field(default=None, alias="suggestion")
123+
124+
def __str__(self):
125+
suggestion = (
126+
""
127+
if self._suggestion is None
128+
else (f" You may have intended to use {self._suggestion}.")
129+
)
130+
return (
131+
f"'#{self.anchor}' is not a valid anchor, neither as a "
132+
f"plain name anchor nor as a JSON Pointer.{suggestion}"
133+
)

referencing/tests/test_core.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,23 @@ def test_lookup_non_existent_anchor(self):
738738
anchor="noSuchAnchor",
739739
)
740740

741+
def test_lookup_invalid_JSON_pointerish_anchor(self):
742+
resolver = Registry().resolver_with_root(
743+
ID_AND_CHILDREN.create_resource(
744+
{
745+
"ID": "http://example.com/",
746+
"foo": {"bar": 12},
747+
},
748+
),
749+
)
750+
751+
valid = resolver.lookup("#/foo/bar")
752+
assert valid.contents == 12
753+
754+
with pytest.raises(exceptions.InvalidAnchor) as e:
755+
resolver.lookup("#foo/bar")
756+
assert " '#/foo/bar'" in str(e.value)
757+
741758
def test_lookup_retrieved_resource(self):
742759
resource = Resource.opaque(contents={"foo": "baz"})
743760
resolver = Registry(retrieve=lambda uri: resource).resolver()

0 commit comments

Comments
 (0)