Skip to content

Commit 60fcbbf

Browse files
committed
Merge branch 'perf_cache_resolving'
* perf_cache_resolving: Squashed 'json/' changes from 9208016..0b657e8 Need to preserve backwards compat for RefResolvers without the new methods. Pass in caches instead of arguments. I give up. Not deprecating these for now, just not used internally. Fix base_uri backwards compatibility. Er, green doesn't work on 2.6, and make running right out of a checkout easier. Wrong docstring. Add back assertions for backwards compat. Wait wat. Remove insanity. Probably should combine these at some point, but for now move them. Really run on the installed package. Begone py.test. Remove 3.3, use pip for installs, use green here too. lxml-cffi is giving obscure errors again. Fix a non-type in the docs. Switch to vcversioner, use repoze.lru only on 2.6, and add extras_require for format. Run tests on the installed package. Newer tox is slightly saner. It's hard to be enthusiastic about tox anymore. Use lru_cache Remove DefragResult. Remove context manager from ref() validation. Perf improvements by using a cache. Add benchmark script. Fix test failures issue #158: TRY to speed-up scope & $ref url-handling by keeping fragments separated from URL (and avoid redunant frag/defrag). Conflicts: jsonschema/tests/test_benchmarks.py
2 parents 1a3203b + a3b999c commit 60fcbbf

18 files changed

+346
-118
lines changed

.gitignore

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,5 @@
1-
.DS_Store
2-
.idea
3-
4-
*.pyc
5-
*.pyo
6-
7-
*.egg-info
8-
_build
9-
build
10-
dist
11-
MANIFEST
12-
13-
.coverage
14-
.coveragerc
15-
coverage
16-
htmlcov
17-
181
_cache
192
_static
203
_templates
214

22-
_trial_temp
23-
24-
.tox
25-
265
TODO

.travis.yml

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,5 @@
11
language: python
22
python:
3-
- "pypy"
4-
- "pypy3"
5-
- "2.6"
63
- "2.7"
7-
- "3.3"
8-
- "3.4"
9-
install:
10-
- python setup.py -q install
114
script:
12-
- if [[ "$(python -c 'import sys; print(sys.version_info[:2])')" == "(2, 6)" ]]; then pip install unittest2; fi
13-
- py.test --tb=native jsonschema
14-
- python -m doctest README.rst
5+
- tox

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
include *.rst
22
include COPYING
33
include tox.ini
4+
include version.txt
45
recursive-include json *

README.rst

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,8 @@ now uses setuptools.
6363
Running the Test Suite
6464
----------------------
6565

66-
``jsonschema`` uses the wonderful `Tox <http://tox.readthedocs.org>`_ for its
67-
test suite. (It really is wonderful, if for some reason you haven't heard of
68-
it, you really should use it for your projects).
69-
70-
Assuming you have ``tox`` installed (perhaps via ``pip install tox`` or your
71-
package manager), just run ``tox`` in the directory of your source checkout to
66+
If you have ``tox`` installed (perhaps via ``pip install tox`` or your
67+
package manager), running``tox`` in the directory of your source checkout will
7268
run ``jsonschema``'s test suite on all of the versions of Python ``jsonschema``
7369
supports. Note that you'll need to have all of those versions installed in
7470
order to run the tests on each of them, otherwise ``tox`` will skip (and fail)

benchmarks/bench.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#!/usr/env/bin python
2+
"""
3+
Benchmark the performance of jsonschema.
4+
5+
Example benchmark:
6+
7+
wget http://swagger.io/v2/schema.json
8+
wget http://petstore.swagger.io/v2/swagger.json
9+
python bench.py -r 5 schema.json swagger.json
10+
11+
"""
12+
from __future__ import print_function
13+
import argparse
14+
import cProfile
15+
import json
16+
import time
17+
18+
import jsonschema
19+
20+
21+
def parse_args():
22+
parser = argparse.ArgumentParser()
23+
parser.add_argument('schema', help="path to a schema used to benchmark")
24+
parser.add_argument('document', help="document to validate with schema")
25+
parser.add_argument('-r', '--repeat', type=int, help="number of iterations")
26+
parser.add_argument('--profile',
27+
help="Enable profiling, write profile to this filepath")
28+
return parser.parse_args()
29+
30+
31+
def run(filename, schema, document):
32+
resolver = jsonschema.RefResolver(
33+
'file://{0}'.format(filename),
34+
schema,
35+
store={schema['id']: schema})
36+
jsonschema.validate(document, schema, resolver=resolver)
37+
38+
39+
def format_time(time_):
40+
return "%.3fms" % (time_ * 1000)
41+
42+
43+
def run_timeit(schema_filename, document_filename, repeat, profile):
44+
with open(schema_filename) as schema_file:
45+
schema = json.load(schema_file)
46+
47+
with open(document_filename) as fh:
48+
document = json.load(fh)
49+
50+
if profile:
51+
profiler = cProfile.Profile()
52+
profiler.enable()
53+
54+
times = []
55+
for _ in range(repeat):
56+
start_time = time.time()
57+
run(schema_filename, schema, document)
58+
times.append(time.time() - start_time)
59+
60+
if profile:
61+
profiler.disable()
62+
profiler.dump_stats(profile)
63+
64+
print(", ".join(map(format_time, sorted(times))))
65+
print("Mean: {0}".format(format_time(sum(times) / repeat)))
66+
67+
68+
def main():
69+
args = parse_args()
70+
run_timeit(args.schema, args.document, args.repeat, args.profile)
71+
72+
73+
if __name__ == "__main__":
74+
main()
File renamed without changes.

json/README.md

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -60,23 +60,69 @@ Who Uses the Test Suite
6060

6161
This suite is being used by:
6262

63-
* [jsck (a fast JSON validator in CoffeeScript)](https://github.com/pandastrike/jsck)
64-
* [json-schema-validator (Java)](https://github.com/fge/json-schema-validator)
65-
* [jsonschema (python)](https://github.com/Julian/jsonschema)
66-
* [aeson-schema (haskell)](https://github.com/timjb/aeson-schema)
67-
* [direct-schema (javascript)](https://github.com/IreneKnapp/direct-schema)
68-
* [jsonschema (javascript)](https://github.com/tdegrunt/jsonschema)
69-
* [JaySchema (javascript)](https://github.com/natesilva/jayschema)
70-
* [z-schema (javascript)](https://github.com/zaggino/z-schema)
71-
* [jassi (javascript)](https://github.com/iclanzan/jassi)
72-
* [json-schema-valid (javascript)](https://github.com/ericgj/json-schema-valid)
73-
* [jesse (Erlang)](https://github.com/klarna/jesse)
74-
* [json-schema (PHP)](https://github.com/justinrainbow/json-schema)
75-
* [gojsonschema (Go)](https://github.com/sigu-399/gojsonschema)
76-
* [json_schema (Dart)](https://github.com/patefacio/json_schema)
77-
* [tv4 (JavaScript)](https://github.com/geraintluff/tv4)
78-
* [Jsonary (JavaScript)](https://github.com/jsonary-js/jsonary)
79-
* [json-schema (Ruby)](https://github.com/hoxworth/json-schema)
63+
### Coffeescript ###
64+
65+
* [jsck](https://github.com/pandastrike/jsck)
66+
67+
### Dart ###
68+
69+
* [json_schema](https://github.com/patefacio/json_schema)
70+
71+
### Erlang ###
72+
73+
* [jesse](https://github.com/klarna/jesse)
74+
75+
### Go ###
76+
77+
* [gojsonschema](https://github.com/sigu-399/gojsonschema)
78+
79+
### Haskell ###
80+
81+
* [aeson-schema](https://github.com/timjb/aeson-schema)
82+
* [hjsonschema](https://github.com/seagreen/hjsonschema)
83+
84+
### Java ###
85+
86+
* [json-schema-validator](https://github.com/fge/json-schema-validator)
87+
88+
### Javascript ###
89+
90+
* [json-schema-benchmark](https://github.com/Muscula/json-schema-benchmark)
91+
* [direct-schema](https://github.com/IreneKnapp/direct-schema)
92+
* [is-my-json-valid](https://github.com/mafintosh/is-my-json-valid)
93+
* [jassi](https://github.com/iclanzan/jassi)
94+
* [JaySchema](https://github.com/natesilva/jayschema)
95+
* [json-schema-valid](https://github.com/ericgj/json-schema-valid)
96+
* [Jsonary](https://github.com/jsonary-js/jsonary)
97+
* [jsonschema](https://github.com/tdegrunt/jsonschema)
98+
* [request-validator](https://github.com/bugventure/request-validator)
99+
* [skeemas](https://github.com/Prestaul/skeemas)
100+
* [tv4](https://github.com/geraintluff/tv4)
101+
* [z-schema](https://github.com/zaggino/z-schema)
102+
103+
### .NET ###
104+
105+
* [Newtonsoft.Json.Schema](https://github.com/JamesNK/Newtonsoft.Json.Schema)
106+
107+
### PHP ###
108+
109+
* [json-schema](https://github.com/justinrainbow/json-schema)
110+
111+
### Python ###
112+
113+
* [jsonschema](https://github.com/Julian/jsonschema)
114+
115+
### Ruby ###
116+
117+
* [json-schema](https://github.com/hoxworth/json-schema)
118+
119+
### Rust ###
120+
121+
* [valico](https://github.com/rustless/valico)
122+
123+
### Swift ###
124+
125+
* [JSONSchema](https://github.com/kylef/JSONSchema.swift)
80126

81127
If you use it as well, please fork and send a pull request adding yourself to
82128
the list :).

json/tests/draft3/additionalProperties.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,25 @@
5555
}
5656
]
5757
},
58+
{
59+
"description":
60+
"additionalProperties can exist by itself",
61+
"schema": {
62+
"additionalProperties": {"type": "boolean"}
63+
},
64+
"tests": [
65+
{
66+
"description": "an additional valid property is valid",
67+
"data": {"foo" : true},
68+
"valid": true
69+
},
70+
{
71+
"description": "an additional invalid property is invalid",
72+
"data": {"foo" : 1},
73+
"valid": false
74+
}
75+
]
76+
},
5877
{
5978
"description": "additionalProperties are allowed by default",
6079
"schema": {"properties": {"foo": {}, "bar": {}}},

json/tests/draft4/additionalProperties.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,25 @@
5555
}
5656
]
5757
},
58+
{
59+
"description":
60+
"additionalProperties can exist by itself",
61+
"schema": {
62+
"additionalProperties": {"type": "boolean"}
63+
},
64+
"tests": [
65+
{
66+
"description": "an additional valid property is valid",
67+
"data": {"foo" : true},
68+
"valid": true
69+
},
70+
{
71+
"description": "an additional invalid property is invalid",
72+
"data": {"foo" : 1},
73+
"valid": false
74+
}
75+
]
76+
},
5877
{
5978
"description": "additionalProperties are allowed by default",
6079
"schema": {"properties": {"foo": {}, "bar": {}}},

jsonschema/__init__.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
Draft3Validator, Draft4Validator, RefResolver, validate
2020
)
2121

22-
23-
__version__ = "2.5.0-dev"
24-
22+
from jsonschema._version import __version__
2523

2624
# flake8: noqa

jsonschema/_validators.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,20 @@ def enum(validator, enums, instance, schema):
190190

191191

192192
def ref(validator, ref, instance, schema):
193-
with validator.resolver.resolving(ref) as resolved:
194-
for error in validator.descend(instance, resolved):
195-
yield error
193+
resolve = getattr(validator.resolver, "resolve", None)
194+
if resolve is None:
195+
with validator.resolver.resolving(ref) as resolved:
196+
for error in validator.descend(instance, resolved):
197+
yield error
198+
else:
199+
scope, resolved = validator.resolver.resolve(ref)
200+
validator.resolver.push_scope(scope)
201+
202+
try:
203+
for error in validator.descend(instance, resolved):
204+
yield error
205+
finally:
206+
validator.resolver.pop_scope()
196207

197208

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

jsonschema/_version.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
# This file is automatically generated by setup.py.
3+
__version__ = '2.3.0.post133'
4+
__sha__ = 'g8ebd5bc'
5+
__revision__ = 'g8ebd5bc'

jsonschema/compat.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
from __future__ import unicode_literals
2-
import sys
31
import operator
2+
import sys
3+
44

55
try:
66
from collections import MutableMapping, Sequence # noqa
77
except ImportError:
88
from collections.abc import MutableMapping, Sequence # noqa
99

1010
PY3 = sys.version_info[0] >= 3
11+
PY26 = sys.version_info[:2] == (2, 6)
1112

1213
if PY3:
1314
zip = zip
15+
from functools import lru_cache
1416
from io import StringIO
1517
from urllib.parse import (
1618
unquote, urljoin, urlunsplit, SplitResult, urlsplit as _urlsplit
@@ -31,6 +33,11 @@
3133
int_types = int, long
3234
iteritems = operator.methodcaller("iteritems")
3335

36+
if PY26:
37+
from repoze.lru import lru_cache
38+
else:
39+
from functools32 import lru_cache
40+
3441

3542
# On python < 3.3 fragments are not handled properly with unknown schemes
3643
def urlsplit(url):

0 commit comments

Comments
 (0)