Skip to content

Commit c46ce21

Browse files
committed
Merge pull request #77 from gazpachoking/canonical_schema_uris
Make sure empty fragment and no fragment are the same in $schema
2 parents 4129584 + 34cd548 commit c46ce21

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

jsonschema.py

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
import socket
2323
import sys
2424

25+
try:
26+
from collections import MutableMapping
27+
except ImportError:
28+
from collections.abc import MutableMapping
29+
2530
try:
2631
import requests
2732
except ImportError:
@@ -48,7 +53,6 @@
4853

4954
FLOAT_TOLERANCE = 10 ** -15
5055
validators = {}
51-
meta_schemas = {}
5256

5357

5458
class _Error(Exception):
@@ -68,6 +72,41 @@ class RefResolutionError(Exception): pass
6872
class UnknownType(Exception): pass
6973

7074

75+
class _URIDict(MutableMapping):
76+
"""
77+
Dictionary which uses normalized URIs as keys.
78+
79+
"""
80+
81+
def normalize(self, uri):
82+
return urlparse.urlsplit(uri).geturl()
83+
84+
def __init__(self, *args, **kwargs):
85+
self.store = dict()
86+
self.store.update(*args, **kwargs)
87+
88+
def __getitem__(self, uri):
89+
return self.store[self.normalize(uri)]
90+
91+
def __setitem__(self, uri, value):
92+
self.store[self.normalize(uri)] = value
93+
94+
def __delitem__(self, uri):
95+
del self.store[self.normalize(uri)]
96+
97+
def __iter__(self):
98+
return iter(self.store)
99+
100+
def __len__(self):
101+
return len(self.store)
102+
103+
def __repr__(self):
104+
return repr(self.store)
105+
106+
107+
meta_schemas = _URIDict()
108+
109+
71110
def validates(version):
72111
"""
73112
Register the decorated validator for a ``version`` of the specification.
@@ -923,7 +962,7 @@ def __init__(self, base_uri, referrer, store=(), cache_remote=True,
923962
self.base_uri = base_uri
924963
self.resolution_scope = base_uri
925964
self.referrer = referrer
926-
self.store = dict(store, **_meta_schemas())
965+
self.store = _URIDict(store, **_meta_schemas())
927966
self.cache_remote = cache_remote
928967
self.handlers = dict(handlers)
929968

@@ -1239,6 +1278,6 @@ def _uniq(container):
12391278

12401279
def validate(instance, schema, cls=None, *args, **kwargs):
12411280
if cls is None:
1242-
cls = meta_schemas.get(schema.get("$schema"), Draft4Validator)
1281+
cls = meta_schemas.get(schema.get("$schema", ""), Draft4Validator)
12431282
cls.check_schema(schema)
12441283
cls(schema, *args, **kwargs).validate(instance)

tests.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,11 @@ def test_draft3_validator_is_chosen(self):
592592
with mock.patch.object(Draft3Validator, "check_schema") as chk_schema:
593593
validate({}, schema)
594594
chk_schema.assert_called_once_with(schema)
595+
# Make sure it works without the empty fragment
596+
schema = {"$schema" : "http://json-schema.org/draft-03/schema"}
597+
with mock.patch.object(Draft3Validator, "check_schema") as chk_schema:
598+
validate({}, schema)
599+
chk_schema.assert_called_once_with(schema)
595600

596601
def test_draft4_validator_is_chosen(self):
597602
schema = {"$schema" : "http://json-schema.org/draft-04/schema#"}

0 commit comments

Comments
 (0)