Skip to content

Commit 6969fbd

Browse files
committed
Merge branch 'master' of https://github.com/Julian/jsonschema into regex_value_validation
2 parents 9d3115a + 1a8ea88 commit 6969fbd

File tree

6 files changed

+124
-84
lines changed

6 files changed

+124
-84
lines changed

README.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,16 @@ Features
7272
of which properties or items failed validation.
7373

7474

75+
Installation
76+
------------
77+
78+
``jsonschema`` is available on `PyPI <https://pypi.org/project/jsonschema/>`_. You can install using `pip <https://pip.pypa.io/en/stable/>`_:
79+
80+
.. code-block:: bash
81+
82+
$ pip install jsonschema
83+
84+
7585
Release Notes
7686
-------------
7787

jsonschema/_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pkgutil
44
import re
55

6-
from jsonschema.compat import str_types, MutableMapping, urlsplit
6+
from jsonschema.compat import MutableMapping, str_types, urlsplit
77

88

99
class URIDict(MutableMapping):

jsonschema/compat.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
"""
2+
Python 2/3 compatibility helpers.
3+
4+
Note: This module is *not* public API.
5+
"""
16
import contextlib
27
import operator
38
import sys
@@ -17,7 +22,7 @@
1722
from urllib.parse import (
1823
unquote, urljoin, urlunsplit, SplitResult, urlsplit as _urlsplit
1924
)
20-
from urllib.request import urlopen
25+
from urllib.request import pathname2url, urlopen
2126
str_types = str,
2227
int_types = int,
2328
iteritems = operator.methodcaller("items")
@@ -27,7 +32,7 @@
2732
from urlparse import (
2833
urljoin, urlunsplit, SplitResult, urlsplit as _urlsplit # noqa
2934
)
30-
from urllib import unquote # noqa
35+
from urllib import pathname2url, unquote # noqa
3136
import urllib2 # noqa
3237
def urlopen(*args, **kwargs):
3338
return contextlib.closing(urllib2.urlopen(*args, **kwargs))

jsonschema/tests/test_jsonschema_test_suite.py

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"""
88

99
import sys
10+
import warnings
1011

1112
from jsonschema import (
1213
Draft3Validator,
@@ -173,27 +174,29 @@ def narrow_unicode_build(test): # pragma: no cover
173174
)
174175

175176

176-
TestDraft3LegacyTypeCheck = DRAFT3.to_unittest_testcase(
177-
# Interestingly the any part couldn't really be done w/the old API.
178-
(
179-
(test for test in each if test.schema != {"type": "any"})
180-
for each in DRAFT3.tests_of(name="type")
181-
),
182-
name="TestDraft3LegacyTypeCheck",
183-
Validator=create(
184-
meta_schema=Draft3Validator.META_SCHEMA,
185-
validators=Draft3Validator.VALIDATORS,
186-
default_types=_DEPRECATED_DEFAULT_TYPES,
187-
),
188-
)
189-
177+
with warnings.catch_warnings():
178+
warnings.simplefilter("ignore", DeprecationWarning)
179+
180+
TestDraft3LegacyTypeCheck = DRAFT3.to_unittest_testcase(
181+
# Interestingly the any part couldn't really be done w/the old API.
182+
(
183+
(test for test in each if test.schema != {"type": "any"})
184+
for each in DRAFT3.tests_of(name="type")
185+
),
186+
name="TestDraft3LegacyTypeCheck",
187+
Validator=create(
188+
meta_schema=Draft3Validator.META_SCHEMA,
189+
validators=Draft3Validator.VALIDATORS,
190+
default_types=_DEPRECATED_DEFAULT_TYPES,
191+
),
192+
)
190193

191-
TestDraft4LegacyTypeCheck = DRAFT4.to_unittest_testcase(
192-
DRAFT4.tests_of(name="type"),
193-
name="TestDraft4LegacyTypeCheck",
194-
Validator=create(
195-
meta_schema=Draft4Validator.META_SCHEMA,
196-
validators=Draft4Validator.VALIDATORS,
197-
default_types=_DEPRECATED_DEFAULT_TYPES,
198-
),
199-
)
194+
TestDraft4LegacyTypeCheck = DRAFT4.to_unittest_testcase(
195+
DRAFT4.tests_of(name="type"),
196+
name="TestDraft4LegacyTypeCheck",
197+
Validator=create(
198+
meta_schema=Draft4Validator.META_SCHEMA,
199+
validators=Draft4Validator.VALIDATORS,
200+
default_types=_DEPRECATED_DEFAULT_TYPES,
201+
),
202+
)

jsonschema/tests/test_validators.py

Lines changed: 70 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,16 @@
2020
_types,
2121
validators,
2222
)
23-
from jsonschema.compat import PY3
23+
from jsonschema.compat import PY3, pathname2url
2424
from jsonschema.tests.compat import mock
2525

2626

27-
if PY3:
28-
from urllib.request import pathname2url
29-
else:
30-
from urllib import pathname2url
31-
32-
3327
def startswith(validator, startswith, instance, schema):
3428
if not instance.startswith(startswith):
3529
yield ValidationError(u"Whoops!")
3630

3731

38-
class TestCreateAndExtend(TestCase):
32+
class TestCreateAndExtend(SynchronousTestCase):
3933
def setUp(self):
4034
self.addCleanup(
4135
self.assertEqual,
@@ -53,14 +47,23 @@ def setUp(self):
5347
)
5448

5549
def test_attrs(self):
56-
self.assertEqual(self.Validator.VALIDATORS, self.validators)
57-
self.assertEqual(self.Validator.META_SCHEMA, self.meta_schema)
58-
self.assertEqual(self.Validator.TYPE_CHECKER, self.type_checker)
50+
self.assertEqual(
51+
(
52+
self.Validator.VALIDATORS,
53+
self.Validator.META_SCHEMA,
54+
self.Validator.TYPE_CHECKER,
55+
), (
56+
self.validators,
57+
self.meta_schema,
58+
self.type_checker,
59+
),
60+
)
5961

6062
# Default types should still be set to the old default if not provided
6163
expected_types = {u"array", u"boolean", u"integer", u"null", u"number",
6264
u"object", u"string"}
6365
self.assertEqual(set(self.Validator.DEFAULT_TYPES), expected_types)
66+
self.assertEqual(len(self.flushWarnings()), 1)
6467

6568
def test_init(self):
6669
schema = {u"startswith": u"foo"}
@@ -132,15 +135,19 @@ def test_extend(self):
132135
(
133136
Extended.VALIDATORS,
134137
Extended.META_SCHEMA,
135-
Extended.DEFAULT_TYPES,
136138
Extended.TYPE_CHECKER,
137139
self.Validator.VALIDATORS,
140+
141+
Extended.DEFAULT_TYPES,
142+
self.flushWarnings()[0]["message"],
138143
), (
139144
dict(original, new=new),
140145
self.Validator.META_SCHEMA,
141-
self.Validator.DEFAULT_TYPES,
142146
self.Validator.TYPE_CHECKER,
143147
original,
148+
149+
self.Validator.DEFAULT_TYPES,
150+
self.flushWarnings()[0]["message"],
144151
),
145152
)
146153

@@ -922,7 +929,7 @@ def test_valid_instances_are_valid(self):
922929
)
923930

924931
def test_invalid_instances_are_not_valid(self):
925-
errors = iter([mock.Mock()])
932+
errors = iter([ValidationError("An error!")])
926933

927934
with mock.patch.object(
928935
self.validator, "iter_errors", return_value=errors,
@@ -979,17 +986,25 @@ def test_string_a_bytestring_is_a_string(self):
979986
self.Validator({"type": "string"}).validate(b"foo")
980987

981988
def test_it_can_validate_with_decimals(self):
982-
schema = {"type": "number"}
983-
validator = self.Validator(
984-
schema, types={"number": (int, float, Decimal)}
989+
schema = {"items": {"type": "number"}}
990+
Validator = validators.extend(
991+
self.Validator,
992+
type_checker=self.Validator.TYPE_CHECKER.redefine(
993+
"number",
994+
lambda checker, thing: isinstance(
995+
thing, (int, float, Decimal),
996+
) and not isinstance(thing, bool),
997+
)
985998
)
986999

987-
for valid in [1, 1.1, Decimal(1) / Decimal(8)]:
988-
validator.validate(valid)
1000+
validator = Validator(schema)
1001+
validator.validate([1, 1.1, Decimal(1) / Decimal(8)])
9891002

990-
for invalid in ["foo", {}, [], True, None]:
991-
with self.assertRaises(ValidationError):
992-
validator.validate(invalid)
1003+
invalid = ["foo", {}, [], True, None]
1004+
self.assertEqual(
1005+
[error.instance for error in validator.iter_errors(invalid)],
1006+
invalid,
1007+
)
9931008

9941009
def test_it_returns_true_for_formats_it_does_not_know_about(self):
9951010
validator = self.Validator(
@@ -1025,6 +1040,35 @@ def check(value):
10251040
# Make sure original cause is attached
10261041
self.assertIs(cm.exception.cause, bad)
10271042

1043+
def test_non_string_custom_type(self):
1044+
non_string_type = object()
1045+
schema = {"type": [non_string_type]}
1046+
Crazy = validators.extend(
1047+
self.Validator,
1048+
type_checker=self.Validator.TYPE_CHECKER.redefine(
1049+
non_string_type,
1050+
lambda checker, thing: isinstance(thing, int),
1051+
)
1052+
)
1053+
Crazy(schema).validate(15)
1054+
1055+
def test_it_properly_formats_tuples_in_errors(self):
1056+
"""
1057+
A tuple instance properly formats validation errors for uniqueItems.
1058+
1059+
See https://github.com/Julian/jsonschema/pull/224
1060+
"""
1061+
TupleValidator = validators.extend(
1062+
self.Validator,
1063+
type_checker=self.Validator.TYPE_CHECKER.redefine(
1064+
"array",
1065+
lambda checker, thing: isinstance(thing, tuple),
1066+
)
1067+
)
1068+
with self.assertRaises(ValidationError) as e:
1069+
TupleValidator({"uniqueItems": True}).validate((1, 1))
1070+
self.assertIn("(1, 1) has non-unique elements", str(e.exception))
1071+
10281072

10291073
class AntiDraft6LeakMixin(object):
10301074
"""
@@ -1083,11 +1127,6 @@ def test_is_type_does_not_evade_bool_if_it_is_being_tested(self):
10831127
self.assertTrue(self.validator.is_type(True, "boolean"))
10841128
self.assertTrue(self.validator.is_valid(True, {"type": "any"}))
10851129

1086-
def test_non_string_custom_types(self):
1087-
schema = {'type': [None]}
1088-
cls = self.Validator(schema, types={None: type(None)})
1089-
cls.validate(None, schema)
1090-
10911130

10921131
class TestDraft4Validator(AntiDraft6LeakMixin, ValidatorTestMixin, TestCase):
10931132
Validator = validators.Draft4Validator
@@ -1097,6 +1136,10 @@ class TestDraft6Validator(ValidatorTestMixin, TestCase):
10971136
Validator = validators.Draft6Validator
10981137

10991138

1139+
class TestDraft7Validator(ValidatorTestMixin, TestCase):
1140+
Validator = validators.Draft7Validator
1141+
1142+
11001143
class TestBuiltinFormats(TestCase):
11011144
"""
11021145
The built-in (specification-defined) formats do not raise type errors.
@@ -1490,35 +1533,6 @@ def test_helpful_error_message_on_failed_pop_scope(self):
14901533
self.assertIn("Failed to pop the scope", str(exc.exception))
14911534

14921535

1493-
class UniqueTupleItemsMixin(object):
1494-
"""
1495-
A tuple instance properly formats validation errors for uniqueItems.
1496-
1497-
See https://github.com/Julian/jsonschema/pull/224
1498-
"""
1499-
1500-
def test_it_properly_formats_an_error_message(self):
1501-
validator = self.Validator(
1502-
schema={"uniqueItems": True},
1503-
types={"array": (tuple,)},
1504-
)
1505-
with self.assertRaises(ValidationError) as e:
1506-
validator.validate((1, 1))
1507-
self.assertIn("(1, 1) has non-unique elements", str(e.exception))
1508-
1509-
1510-
class TestDraft6UniqueTupleItems(UniqueTupleItemsMixin, TestCase):
1511-
Validator = validators.Draft6Validator
1512-
1513-
1514-
class TestDraft4UniqueTupleItems(UniqueTupleItemsMixin, TestCase):
1515-
Validator = validators.Draft4Validator
1516-
1517-
1518-
class TestDraft3UniqueTupleItems(UniqueTupleItemsMixin, TestCase):
1519-
Validator = validators.Draft3Validator
1520-
1521-
15221536
def sorted_errors(errors):
15231537
def key(error):
15241538
return (

jsonschema/validators.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,16 @@
99

1010
from jsonschema import _utils, _validators, _types
1111
from jsonschema.compat import (
12-
Sequence, urljoin, urlsplit, urldefrag, unquote, urlopen,
13-
str_types, int_types, iteritems, lru_cache,
12+
Sequence,
13+
int_types,
14+
iteritems,
15+
lru_cache,
16+
str_types,
17+
unquote,
18+
urldefrag,
19+
urljoin,
20+
urlopen,
21+
urlsplit,
1422
)
1523
from jsonschema.exceptions import (
1624
RefResolutionError,

0 commit comments

Comments
 (0)