diff --git a/jsonschema/_utils.py b/jsonschema/_utils.py index 10e7bf8..044475c 100644 --- a/jsonschema/_utils.py +++ b/jsonschema/_utils.py @@ -3,7 +3,7 @@ import json import re import os -from jsonschema.compat import str_types, urlparse, MutableMapping +from jsonschema.compat import str_types, MutableMapping, urlsplit class URIDict(MutableMapping): @@ -13,7 +13,7 @@ class URIDict(MutableMapping): """ def normalize(self, uri): - return urlparse.urlsplit(uri).geturl() + return urlsplit(uri).geturl() def __init__(self, *args, **kwargs): self.store = dict() diff --git a/jsonschema/compat.py b/jsonschema/compat.py index 44c6ede..e5394f0 100644 --- a/jsonschema/compat.py +++ b/jsonschema/compat.py @@ -11,15 +11,18 @@ PY3 = sys.version_info[0] >= 3 if PY3: zip = zip - from urllib import parse as urlparse - from urllib.parse import unquote + from urllib.parse import ( + unquote, urljoin, urlunsplit, SplitResult, urlsplit as _urlsplit + ) from urllib.request import urlopen str_types = str, int_types = int, iteritems = operator.methodcaller("items") else: from itertools import izip as zip # noqa - import urlparse # noqa + from urlparse import ( + urljoin, urlunsplit, SplitResult, urlsplit as _urlsplit # noqa + ) from urllib import unquote # noqa from urllib2 import urlopen # noqa str_types = basestring @@ -27,4 +30,22 @@ else: iteritems = operator.methodcaller("iteritems") +# On python < 3.3 fragments are not handled properly with unknown schemes +def urlsplit(url): + scheme, netloc, path, query, fragment = _urlsplit(url) + if "#" in path: + path, fragment = path.split("#", 1) + return SplitResult(scheme, netloc, path, query, fragment) + + +def urldefrag(url): + if "#" in url: + s, n, p, q, frag = urlsplit(url) + defrag = urlunsplit((s, n, p, q, '')) + else: + defrag = url + frag = '' + return defrag, frag + + # flake8: noqa diff --git a/jsonschema/validators.py b/jsonschema/validators.py index 9741125..4dd71e5 100644 --- a/jsonschema/validators.py +++ b/jsonschema/validators.py @@ -15,7 +15,7 @@ except ImportError: from jsonschema import _utils from jsonschema.compat import ( - PY3, Sequence, urlparse, unquote, urlopen, str_types, int_types, iteritems, + PY3, Sequence, urljoin, urlsplit, urldefrag, unquote, urlopen, str_types, int_types, iteritems, ) from jsonschema._format import FormatError @@ -629,7 +629,7 @@ class RefResolver(object): @contextlib.contextmanager def in_scope(self, scope): old_scope = self.resolution_scope - self.resolution_scope = urlparse.urljoin(old_scope, scope) + self.resolution_scope = urljoin(old_scope, scope) try: yield finally: @@ -645,8 +645,8 @@ class RefResolver(object): """ - full_uri = urlparse.urljoin(self.resolution_scope, ref) - uri, fragment = urlparse.urldefrag(full_uri) + full_uri = urljoin(self.resolution_scope, ref) + uri, fragment = urldefrag(full_uri) if not uri: uri = self.base_uri @@ -718,7 +718,7 @@ class RefResolver(object): """ - scheme = urlparse.urlsplit(uri).scheme + scheme = urlsplit(uri).scheme if scheme in self.handlers: result = self.handlers[scheme](uri) diff --git a/test_jsonschema.py b/test_jsonschema.py index 11d8cd8..7a07904 100644 --- a/test_jsonschema.py +++ b/test_jsonschema.py @@ -861,11 +861,11 @@ class TestRefResolver(unittest.TestCase): self.assertEqual(resolved, self.referrer["properties"]["foo"]) def test_it_resolves_local_refs_with_id(self): - schema = {"id": "/bar/schema#", "a": {"foo": "bar"}} + schema = {"id": "foo://bar/schema#", "a": {"foo": "bar"}} resolver = RefResolver.from_schema(schema) with resolver.resolving("#/a") as resolved: self.assertEqual(resolved, schema["a"]) - with resolver.resolving("/bar/schema#/a") as resolved: + with resolver.resolving("foo://bar/schema#/a") as resolved: self.assertEqual(resolved, schema["a"]) def test_it_retrieves_stored_refs(self):