Skip to content

Commit c763ab9

Browse files
committed
Apply built-in formats only to strings, otherwise ignore.
1 parent 6995283 commit c763ab9

4 files changed

Lines changed: 61 additions & 12 deletions

File tree

jsonschema/_format.py

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import re
33
import socket
44

5+
from jsonschema.compat import str_types
56
from jsonschema.exceptions import FormatError
67

78

@@ -117,24 +118,32 @@ def wrap(func):
117118

118119
@_checks_drafts("email")
119120
def is_email(instance):
121+
if not isinstance(instance, str_types):
122+
return True
120123
return "@" in instance
121124

122125

123-
_checks_drafts(draft3="ip-address", draft4="ipv4", raises=socket.error)(
124-
socket.inet_aton
125-
)
126+
@_checks_drafts(draft3="ip-address", draft4="ipv4", raises=socket.error)
127+
def is_ipv4(instance):
128+
if not isinstance(instance, str_types):
129+
return True
130+
return socket.inet_aton(instance)
126131

127132

128133
if hasattr(socket, "inet_pton"):
129134
@_checks_drafts("ipv6", raises=socket.error)
130135
def is_ipv6(instance):
136+
if not isinstance(instance, str_types):
137+
return True
131138
return socket.inet_pton(socket.AF_INET6, instance)
132139

133140

134141
_host_name_re = re.compile(r"^[A-Za-z0-9][A-Za-z0-9\.\-]{1,255}$")
135142

136143
@_checks_drafts(draft3="host-name", draft4="hostname")
137144
def is_host_name(instance):
145+
if not isinstance(instance, str_types):
146+
return True
138147
if not _host_name_re.match(instance):
139148
return False
140149
components = instance.split(".")
@@ -151,6 +160,8 @@ def is_host_name(instance):
151160
else:
152161
@_checks_drafts("uri", raises=ValueError)
153162
def is_uri(instance):
163+
if not isinstance(instance, str_types):
164+
return True
154165
return rfc3987.parse(instance, rule="URI")
155166

156167

@@ -162,22 +173,37 @@ def is_uri(instance):
162173
except ImportError:
163174
pass
164175
else:
165-
_err = (ValueError, isodate.ISO8601Error)
166-
_checks_drafts("date-time", raises=_err)(isodate.parse_datetime)
176+
@_checks_drafts("date-time", raises=(ValueError, isodate.ISO8601Error))
177+
def is_date(instance):
178+
if not isinstance(instance, str_types):
179+
return True
180+
return isodate.parse_datetime(instance)
167181
else:
168-
_checks_drafts("date-time")(strict_rfc3339.validate_rfc3339)
182+
@_checks_drafts("date-time")
183+
def is_date(instance):
184+
if not isinstance(instance, str_types):
185+
return True
186+
return strict_rfc3339.validate_rfc3339(instance)
169187

170188

171-
_checks_drafts("regex", raises=re.error)(re.compile)
189+
@_checks_drafts("regex", raises=re.error)
190+
def is_regex(instance):
191+
if not isinstance(instance, str_types):
192+
return True
193+
return re.compile(instance)
172194

173195

174196
@_checks_drafts(draft3="date", raises=ValueError)
175197
def is_date(instance):
198+
if not isinstance(instance, str_types):
199+
return True
176200
return datetime.datetime.strptime(instance, "%Y-%m-%d")
177201

178202

179203
@_checks_drafts(draft3="time", raises=ValueError)
180204
def is_time(instance):
205+
if not isinstance(instance, str_types):
206+
return True
181207
return datetime.datetime.strptime(instance, "%H:%M:%S")
182208

183209

@@ -192,7 +218,10 @@ def is_css_color_code(instance):
192218

193219
@_checks_drafts(draft3="color", raises=(ValueError, TypeError))
194220
def is_css21_color(instance):
195-
if instance.lower() in webcolors.css21_names_to_hex:
221+
if (
222+
not isinstance(instance, str_types) or
223+
instance.lower() in webcolors.css21_names_to_hex
224+
):
196225
return True
197226
return is_css_color_code(instance)
198227

jsonschema/tests/test_exceptions.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
import mock
2-
31
from jsonschema import Draft4Validator, exceptions
4-
from jsonschema.tests.compat import unittest
2+
from jsonschema.tests.compat import mock, unittest
53

64

75
class TestBestMatch(unittest.TestCase):

jsonschema/tests/test_validators.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,28 @@ class TestDraft4Validator(ValidatorTestMixin, unittest.TestCase):
602602
validator_class = Draft4Validator
603603

604604

605+
class TestBuiltinFormats(unittest.TestCase):
606+
"""
607+
The built-in (specification-defined) formats do not raise type errors.
608+
609+
If an instance or value is not a string, it should be ignored.
610+
611+
"""
612+
613+
614+
for format in FormatChecker.checkers:
615+
def test(self, format=format):
616+
v = Draft4Validator({"format": format}, format_checker=FormatChecker())
617+
v.validate(123)
618+
619+
name = "test_{0}_ignores_non_strings".format(format)
620+
if not PY3:
621+
name = name.encode("utf-8")
622+
test.__name__ = name
623+
setattr(TestBuiltinFormats, name, test)
624+
del test # Ugh py.test. Stop discovering top level tests.
625+
626+
605627
class TestValidatorFor(unittest.TestCase):
606628
def test_draft_3(self):
607629
schema = {"$schema" : "http://json-schema.org/draft-03/schema"}

jsonschema/validators.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
PY3, Sequence, urljoin, urlsplit, urldefrag, unquote, urlopen,
1515
str_types, int_types, iteritems,
1616
)
17-
from jsonschema.exceptions import ErrorTree # For backwards compatibility
17+
from jsonschema.exceptions import ErrorTree # Backwards compatibility # noqa
1818
from jsonschema.exceptions import RefResolutionError, SchemaError, UnknownType
1919

2020

0 commit comments

Comments
 (0)