Skip to content

Commit d0609d9

Browse files
committed
Possible to breakout of loop for a single node (ie for $ref).
Neglibly slower, BUT reduced stdev and simpler main-loop code.
1 parent f0422be commit d0609d9

File tree

4 files changed

+49
-29
lines changed

4 files changed

+49
-29
lines changed

jsonschema/_validators.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import re
22

33
from jsonschema import _utils
4-
from jsonschema.exceptions import FormatError, ValidationError
4+
from jsonschema.exceptions import FormatError, ValidationError, BreakLoopException
55
from jsonschema.compat import iteritems
66

77

@@ -196,6 +196,7 @@ def ref(validator, ref, instance, schema):
196196
with validator.resolver.resolving(ref) as resolved:
197197
for error in validator.descend(instance, resolved):
198198
yield error
199+
raise BreakLoopException()
199200

200201

201202
def type_draft3(validator, types, instance, schema):

jsonschema/exceptions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ def __unicode__(self):
165165
if PY3:
166166
__str__ = __unicode__
167167

168+
class BreakLoopException(Exception):
169+
pass
168170

169171
class ErrorTree(object):
170172
"""

jsonschema/tests/test_benchmarks.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,13 @@ def test_V3_meta_schema(self):
4343
4444
master-19-Aug (9f18270): Time @ Xeon 3.2GHz::
4545
46-
278 runs in 2.00 sec
47-
ms/run: mean(7.17), std(0.56), MIN(6.50), MAX(10.51)
46+
286 runs in 2.00 sec
47+
ms/run: mean(6.98), std(0.35), MIN(6.50), MAX(9.50)
48+
49+
break_looop: Time @ Xeon 3.2GHz::
50+
51+
283 runs in 2.00 sec
52+
ms/run: mean(7.05), std(0.28), MIN(6.50), MAX(9.50)
4853
"""
4954

5055
stats = []
@@ -63,8 +68,13 @@ def test_V4_meta_schema(self):
6368
6469
master-19-Aug (9f18270): Time @ Xeon 3.2GHz::
6570
66-
164 runs in 2.00 sec
67-
ms/run: mean(12.15), std(1.36), MIN(11.01), MAX(21.02)
71+
174 runs in 2.01 sec
72+
ms/run: mean(11.47), std(0.36), MIN(11.00), MAX(13.00)
73+
74+
break_looop: Time @ Xeon 3.2GHz::
75+
76+
173 runs in 2.01 sec
77+
ms/run: mean(11.53), std(0.28), MIN(11.00), MAX(13.00)
6878
"""
6979

7080
stats = []
@@ -83,8 +93,13 @@ def test_both_meta_schemas(self):
8393
8494
master-19-Aug (9f18270): Time @ Xeon 3.2GHz::
8595
86-
104 runs in 2.01 sec
87-
ms/run: mean(19.13), std(1.12), MIN(18.01), MAX(23.02)
96+
108 runs in 2.00 sec
97+
ms/run: mean(18.38), std(0.35), MIN(18.00), MAX(19.50)
98+
99+
break_looop: Time @ Xeon 3.2GHz::
100+
101+
107 runs in 2.01 sec
102+
ms/run: mean(18.62), std(0.38), MIN(18.00), MAX(20.00)
88103
"""
89104

90105
v_classes = [Draft3Validator, Draft4Validator]
@@ -105,8 +120,13 @@ def test_ref_model(self):
105120
106121
master-19-Aug (9f18270): Time @ Xeon 3.2GHz::
107122
108-
16 runs in 2.00 sec
109-
ms/run: mean(117.80), std(4.32), MIN(113.09), MAX(127.60)
123+
18 runs in 2.07 sec
124+
ms/run: mean(109.21), std(1.33), MIN(107.52), MAX(112.52)
125+
126+
break_looop: Time @ Xeon 3.2GHz::
127+
128+
18 runs in 2.09 sec
129+
ms/run: mean(109.97), std(0.80), MIN(109.02), MAX(112.02)
110130
"""
111131

112132
stats = []

jsonschema/validators.py

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
str_types, int_types, iteritems,
1616
)
1717
from jsonschema.exceptions import ErrorTree # Backwards compatibility # noqa
18-
from jsonschema.exceptions import RefResolutionError, SchemaError, UnknownType
18+
from jsonschema.exceptions import RefResolutionError, SchemaError, UnknownType, BreakLoopException
1919

2020

2121
_unset = _utils.Unset()
@@ -80,29 +80,26 @@ def iter_errors(self, instance, _schema=None):
8080
_schema = self.schema
8181

8282
with self.resolver.in_scope(_schema.get(u"id", u"")):
83-
ref = _schema.get(u"$ref")
84-
if ref is not None:
85-
validators = [(u"$ref", ref)]
86-
else:
87-
validators = iteritems(_schema)
88-
89-
for k, v in validators:
83+
for k, v in iteritems(_schema):
9084
validator = self.VALIDATORS.get(k)
9185
if validator is None:
9286
continue
9387

94-
errors = validator(self, v, instance, _schema) or ()
95-
for error in errors:
96-
# set details if not already set by the called fn
97-
error._set(
98-
validator=k,
99-
validator_value=v,
100-
instance=instance,
101-
schema=_schema,
102-
)
103-
if k != u"$ref":
104-
error.schema_path.appendleft(k)
105-
yield error
88+
try:
89+
errors = validator(self, v, instance, _schema) or ()
90+
for error in errors:
91+
# set details if not already set by the called fn
92+
error._set(
93+
validator=k,
94+
validator_value=v,
95+
instance=instance,
96+
schema=_schema,
97+
)
98+
if k != u"$ref":
99+
error.schema_path.appendleft(k)
100+
yield error
101+
except BreakLoopException:
102+
break
106103

107104
def descend(self, instance, schema, path=None, schema_path=None):
108105
for error in self.iter_errors(instance, schema):

0 commit comments

Comments
 (0)