Use lru_cache
This commit is contained in:
parent
ca59f3fa87
commit
ee1a256fc8
|
@ -19,8 +19,6 @@ from jsonschema.validators import (
|
|||
Draft3Validator, Draft4Validator, RefResolver, validate
|
||||
)
|
||||
|
||||
|
||||
__version__ = "2.5.0-dev"
|
||||
|
||||
from jsonschema.version import __version__
|
||||
|
||||
# flake8: noqa
|
||||
|
|
|
@ -38,22 +38,6 @@ class URIDict(MutableMapping):
|
|||
return repr(self.store)
|
||||
|
||||
|
||||
class Cache(object):
|
||||
"""Cache the result of a function, using the arguments to the function as
|
||||
the key.
|
||||
"""
|
||||
|
||||
def __init__(self, func):
|
||||
self.func = func
|
||||
self._cache = {}
|
||||
|
||||
def __call__(self, *args):
|
||||
if args in self._cache:
|
||||
return self._cache[args]
|
||||
self._cache[args] = value = self.func(*args)
|
||||
return value
|
||||
|
||||
|
||||
class Unset(object):
|
||||
"""
|
||||
An as-of-yet unset attribute or unprovided default parameter.
|
||||
|
|
|
@ -13,6 +13,7 @@ PY3 = sys.version_info[0] >= 3
|
|||
|
||||
if PY3:
|
||||
zip = zip
|
||||
from functools import lru_cache
|
||||
from io import StringIO
|
||||
from urllib.parse import (
|
||||
unquote, urljoin, urlunsplit, SplitResult, urlsplit as _urlsplit
|
||||
|
@ -23,6 +24,7 @@ if PY3:
|
|||
iteritems = operator.methodcaller("items")
|
||||
else:
|
||||
from itertools import izip as zip # noqa
|
||||
from repoze.lru import lru_cache
|
||||
from StringIO import StringIO
|
||||
from urlparse import (
|
||||
urljoin, urlunsplit, SplitResult, urlsplit as _urlsplit # noqa
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
from collections import deque
|
||||
from contextlib import contextmanager
|
||||
import json
|
||||
|
||||
from jsonschema import FormatChecker, ValidationError
|
||||
|
@ -870,6 +869,13 @@ class TestRefResolver(unittest.TestCase):
|
|||
pass
|
||||
self.assertEqual(str(err.exception), "Oh no! What's this?")
|
||||
|
||||
def test_helpful_error_message_on_failed_pop_scope(self):
|
||||
resolver = RefResolver("", {})
|
||||
resolver.pop_scope()
|
||||
with self.assertRaises(RefResolutionError) as exc:
|
||||
resolver.pop_scope()
|
||||
self.assertIn("Failed to pop the scope", str(exc.exception))
|
||||
|
||||
|
||||
def sorted_errors(errors):
|
||||
def key(error):
|
||||
|
|
|
@ -12,7 +12,7 @@ except ImportError:
|
|||
from jsonschema import _utils, _validators
|
||||
from jsonschema.compat import (
|
||||
Sequence, urljoin, urlsplit, urldefrag, unquote, urlopen,
|
||||
str_types, int_types, iteritems,
|
||||
str_types, int_types, iteritems, lru_cache,
|
||||
)
|
||||
from jsonschema.exceptions import ErrorTree # Backwards compatibility # noqa
|
||||
from jsonschema.exceptions import RefResolutionError, SchemaError, UnknownType
|
||||
|
@ -233,18 +233,22 @@ class RefResolver(object):
|
|||
first resolution
|
||||
:argument dict handlers: a mapping from URI schemes to functions that
|
||||
should be used to retrieve them
|
||||
|
||||
:arguments callable cache_func: a function decorator used to cache
|
||||
expensive calls. Should support the `functools.lru_cache` interface.
|
||||
:argument int cache_maxsize: number of items to store in the cache. Set
|
||||
this to 0 to disable caching. Defaults to 1000.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, base_uri, referrer, store=(), cache_remote=True, handlers=(),
|
||||
cache_func=lru_cache, cache_maxsize=1000,
|
||||
):
|
||||
# This attribute is not used, it is for backwards compatibility
|
||||
self.referrer = referrer
|
||||
self.cache_remote = cache_remote
|
||||
self.handlers = dict(handlers)
|
||||
|
||||
self.scopes_stack = [base_uri]
|
||||
self._scopes_stack = [base_uri]
|
||||
self.store = _utils.URIDict(
|
||||
(id, validator.META_SCHEMA)
|
||||
for id, validator in iteritems(meta_schemas)
|
||||
|
@ -252,8 +256,8 @@ class RefResolver(object):
|
|||
self.store.update(store)
|
||||
self.store[base_uri] = referrer
|
||||
|
||||
self.urljoin_cache = _utils.Cache(urljoin)
|
||||
self.resolve_cache = _utils.Cache(self.resolve_from_url)
|
||||
self._urljoin_cache = cache_func(cache_maxsize)(urljoin)
|
||||
self._resolve_cache = cache_func(cache_maxsize)(self.resolve_from_url)
|
||||
|
||||
@classmethod
|
||||
def from_schema(cls, schema, *args, **kwargs):
|
||||
|
@ -268,15 +272,21 @@ class RefResolver(object):
|
|||
return cls(schema.get(u"id", u""), schema, *args, **kwargs)
|
||||
|
||||
def push_scope(self, scope):
|
||||
self.scopes_stack.append(
|
||||
self.urljoin_cache(self.resolution_scope, scope))
|
||||
self._scopes_stack.append(
|
||||
self._urljoin_cache(self.resolution_scope, scope))
|
||||
|
||||
def pop_scope(self):
|
||||
self.scopes_stack.pop()
|
||||
try:
|
||||
self._scopes_stack.pop()
|
||||
except IndexError:
|
||||
raise RefResolutionError(
|
||||
"Failed to pop the scope from an empty stack. "
|
||||
"`pop_scope()` should only be called once for every "
|
||||
"`push_scope()`")
|
||||
|
||||
@property
|
||||
def resolution_scope(self):
|
||||
return self.scopes_stack[-1]
|
||||
return self._scopes_stack[-1]
|
||||
|
||||
|
||||
# Deprecated, this function is no longer used, but is preserved for
|
||||
|
@ -308,8 +318,8 @@ class RefResolver(object):
|
|||
:argument str ref: reference to resolve
|
||||
|
||||
"""
|
||||
url = self.urljoin_cache(self.resolution_scope, ref)
|
||||
return url, self.resolve_cache(url)
|
||||
url = self._urljoin_cache(self.resolution_scope, ref)
|
||||
return url, self._resolve_cache(url)
|
||||
|
||||
def resolve_from_url(self, url):
|
||||
url, fragment = urldefrag(url)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
__version__ = "2.5.0-dev"
|
15
setup.py
15
setup.py
|
@ -1,7 +1,12 @@
|
|||
import os.path
|
||||
from setuptools import setup
|
||||
import sys
|
||||
|
||||
from jsonschema import __version__
|
||||
|
||||
# Load __version__ info globals without importing anything
|
||||
with open(
|
||||
os.path.join(os.path.dirname(__file__), 'jsonschema', 'version.py')
|
||||
) as fh:
|
||||
exec(fh.read())
|
||||
|
||||
with open("README.rst") as readme:
|
||||
long_description = readme.read()
|
||||
|
@ -21,6 +26,11 @@ classifiers = [
|
|||
"Programming Language :: Python :: Implementation :: PyPy",
|
||||
]
|
||||
|
||||
install_requires = []
|
||||
|
||||
if sys.version_info < (3, 2):
|
||||
install_requires.append('repoze.lru >= 0.6')
|
||||
|
||||
setup(
|
||||
name="jsonschema",
|
||||
version=__version__,
|
||||
|
@ -34,4 +44,5 @@ setup(
|
|||
long_description=long_description,
|
||||
url="http://github.com/Julian/jsonschema",
|
||||
entry_points={"console_scripts": ["jsonschema = jsonschema.cli:main"]},
|
||||
install_requires=install_requires,
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue