Skip to content

Commit 90665d6

Browse files
committed
Normalize JSON Schema IDs to strip empty fragments.
This is discouraged by the spec, albeit still allowed. Future versions may fully make it an error, which is why it seems to make sense to make this JSON Schema-specific (rather than e.g. doing it as part of Resource.id) as some other spec may allow it and have different behavior to my current understanding. Refs: python-jsonschema/jsonschema#1064
1 parent 5100d87 commit 90665d6

File tree

2 files changed

+51
-8
lines changed

2 files changed

+51
-8
lines changed

referencing/jsonschema.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,25 @@ class UnknownDialect(Exception):
3636
def _dollar_id(contents: Schema) -> URI | None:
3737
if isinstance(contents, bool):
3838
return
39-
return contents.get("$id")
39+
id = contents.get("$id")
40+
if id is not None:
41+
return id.rstrip("#")
4042

4143

4244
def _legacy_dollar_id(contents: Schema) -> URI | None:
4345
if isinstance(contents, bool) or "$ref" in contents:
4446
return
4547
id = contents.get("$id")
4648
if id is not None and not id.startswith("#"):
47-
return id
49+
return id.rstrip("#")
4850

4951

5052
def _legacy_id(contents: ObjectSchema) -> URI | None:
5153
if "$ref" in contents:
5254
return
5355
id = contents.get("id")
5456
if id is not None and not id.startswith("#"):
55-
return id
57+
return id.rstrip("#")
5658

5759

5860
def _anchor(
@@ -547,10 +549,10 @@ def maybe_in_subresource(
547549
for dialect_id, specification in [
548550
("https://json-schema.org/draft/2020-12/schema", DRAFT202012),
549551
("https://json-schema.org/draft/2019-09/schema", DRAFT201909),
550-
("http://json-schema.org/draft-07/schema#", DRAFT7),
551-
("http://json-schema.org/draft-06/schema#", DRAFT6),
552-
("http://json-schema.org/draft-04/schema#", DRAFT4),
553-
("http://json-schema.org/draft-03/schema#", DRAFT3),
552+
("http://json-schema.org/draft-07/schema", DRAFT7),
553+
("http://json-schema.org/draft-06/schema", DRAFT6),
554+
("http://json-schema.org/draft-04/schema", DRAFT4),
555+
("http://json-schema.org/draft-03/schema", DRAFT3),
554556
]
555557
},
556558
)
@@ -569,7 +571,7 @@ def specification_with(
569571
570572
if the given ``dialect_id`` isn't known
571573
"""
572-
resource = _SPECIFICATIONS.get(dialect_id)
574+
resource = _SPECIFICATIONS.get(dialect_id.rstrip("#"))
573575
if resource is not None:
574576
return resource.contents
575577
if default is None: # type: ignore[reportUnnecessaryComparison]

referencing/tests/test_jsonschema.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,22 @@ def test_id_of_mapping(id, specification):
6565
assert specification.id_of({id: uri}) == uri
6666

6767

68+
@pytest.mark.parametrize(
69+
"id, specification",
70+
[
71+
("$id", referencing.jsonschema.DRAFT202012),
72+
("$id", referencing.jsonschema.DRAFT201909),
73+
("$id", referencing.jsonschema.DRAFT7),
74+
("$id", referencing.jsonschema.DRAFT6),
75+
("id", referencing.jsonschema.DRAFT4),
76+
("id", referencing.jsonschema.DRAFT3),
77+
],
78+
)
79+
def test_id_of_empty_fragment(id, specification):
80+
uri = "http://example.com/some-schema"
81+
assert specification.id_of({id: uri + "#"}) == uri
82+
83+
6884
@pytest.mark.parametrize(
6985
"specification",
7086
[
@@ -140,6 +156,31 @@ def test_specification_with(uri, expected):
140156
assert referencing.jsonschema.specification_with(uri) == expected
141157

142158

159+
@pytest.mark.parametrize(
160+
"uri, expected",
161+
[
162+
(
163+
"http://json-schema.org/draft-07/schema",
164+
referencing.jsonschema.DRAFT7,
165+
),
166+
(
167+
"http://json-schema.org/draft-06/schema",
168+
referencing.jsonschema.DRAFT6,
169+
),
170+
(
171+
"http://json-schema.org/draft-04/schema",
172+
referencing.jsonschema.DRAFT4,
173+
),
174+
(
175+
"http://json-schema.org/draft-03/schema",
176+
referencing.jsonschema.DRAFT3,
177+
),
178+
],
179+
)
180+
def test_specification_with_no_empty_fragment(uri, expected):
181+
assert referencing.jsonschema.specification_with(uri) == expected
182+
183+
143184
def test_specification_with_unknown_dialect():
144185
dialect_id = "http://example.com/unknown-json-schema-dialect-id"
145186
with pytest.raises(referencing.jsonschema.UnknownDialect) as excinfo:

0 commit comments

Comments
 (0)