summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Berman <Julian@GrayVines.com>2021-08-18 09:23:00 +0100
committerJulian Berman <Julian@GrayVines.com>2021-08-18 09:23:00 +0100
commitd104bdbe2ce3f283e4e2bbf2a5fe7f6f7d6f7280 (patch)
tree9275f20a02d7c91f2a8cb509af90040fa2a624b9
parent7f677965d26846e20e2e417f6201bb7e2cde554e (diff)
downloadjsonschema-d104bdbe2ce3f283e4e2bbf2a5fe7f6f7d6f7280.tar.gz
May as well add support for Draft 2019 as well.
recursiveRef is broken in the same way dynamicRef is.
-rw-r--r--docs/validate.rst2
-rw-r--r--jsonschema/__init__.py2
-rw-r--r--jsonschema/_format.py30
-rw-r--r--jsonschema/_legacy_validators.py18
-rw-r--r--jsonschema/_types.py3
-rw-r--r--jsonschema/_validators.py25
-rw-r--r--jsonschema/schemas/draft2019-09.json42
-rw-r--r--jsonschema/schemas/draft2019-09/applicator.json56
-rw-r--r--jsonschema/schemas/draft2019-09/content.json17
-rw-r--r--jsonschema/schemas/draft2019-09/core.json57
-rw-r--r--jsonschema/schemas/draft2019-09/format.json14
-rw-r--r--jsonschema/schemas/draft2019-09/hyper-schema.json29
-rw-r--r--jsonschema/schemas/draft2019-09/meta-data.json37
-rw-r--r--jsonschema/schemas/draft2019-09/validation.json98
-rw-r--r--jsonschema/tests/test_jsonschema_test_suite.py38
-rw-r--r--jsonschema/validators.py56
16 files changed, 488 insertions, 36 deletions
diff --git a/docs/validate.rst b/docs/validate.rst
index b9d62f7..a049bd6 100644
--- a/docs/validate.rst
+++ b/docs/validate.rst
@@ -237,6 +237,8 @@ which each included validator class implements.
.. autoclass:: Draft202012Validator
+.. autoclass:: Draft201909Validator
+
.. autoclass:: Draft7Validator
.. autoclass:: Draft6Validator
diff --git a/jsonschema/__init__.py b/jsonschema/__init__.py
index c1cb2e9..c39082c 100644
--- a/jsonschema/__init__.py
+++ b/jsonschema/__init__.py
@@ -14,6 +14,7 @@ from jsonschema._format import (
draft4_format_checker,
draft6_format_checker,
draft7_format_checker,
+ draft201909_format_checker,
draft202012_format_checker,
)
from jsonschema._types import TypeChecker
@@ -29,6 +30,7 @@ from jsonschema.validators import (
Draft4Validator,
Draft6Validator,
Draft7Validator,
+ Draft201909Validator,
Draft202012Validator,
RefResolver,
validate,
diff --git a/jsonschema/_format.py b/jsonschema/_format.py
index 5d610ef..1395a59 100644
--- a/jsonschema/_format.py
+++ b/jsonschema/_format.py
@@ -132,6 +132,7 @@ draft3_format_checker = FormatChecker()
draft4_format_checker = FormatChecker()
draft6_format_checker = FormatChecker()
draft7_format_checker = FormatChecker()
+draft201909_format_checker = FormatChecker()
draft202012_format_checker = FormatChecker()
_draft_checkers = dict(
@@ -139,6 +140,7 @@ _draft_checkers = dict(
draft4=draft4_format_checker,
draft6=draft6_format_checker,
draft7=draft7_format_checker,
+ draft201909=draft201909_format_checker,
draft202012=draft202012_format_checker,
)
@@ -149,6 +151,7 @@ def _checks_drafts(
draft4=None,
draft6=None,
draft7=None,
+ draft201909=None,
draft202012=None,
raises=(),
):
@@ -156,6 +159,7 @@ def _checks_drafts(
draft4 = draft4 or name
draft6 = draft6 or name
draft7 = draft7 or name
+ draft201909 = draft201909 or name
draft202012 = draft202012 or name
def wrap(func):
@@ -167,6 +171,10 @@ def _checks_drafts(
func = _draft_checkers["draft6"].checks(draft6, raises)(func)
if draft7:
func = _draft_checkers["draft7"].checks(draft7, raises)(func)
+ if draft201909:
+ func = _draft_checkers["draft201909"].checks(draft201909, raises)(
+ func,
+ )
if draft202012:
func = _draft_checkers["draft202012"].checks(draft202012, raises)(
func,
@@ -176,7 +184,8 @@ def _checks_drafts(
# deprecation. See https://github.com/Julian/jsonschema/issues/519
# and test_format_checkers_come_with_defaults
FormatChecker.cls_checks(
- draft202012 or draft7 or draft6 or draft4 or draft3, raises,
+ draft202012 or draft201909 or draft7 or draft6 or draft4 or draft3,
+ raises,
)(func)
return func
return wrap
@@ -195,6 +204,7 @@ def is_email(instance):
draft4="ipv4",
draft6="ipv4",
draft7="ipv4",
+ draft201909="ipv4",
draft202012="ipv4",
raises=ipaddress.AddressValueError,
)
@@ -222,6 +232,7 @@ else:
draft4="hostname",
draft6="hostname",
draft7="hostname",
+ draft201909="hostname",
draft202012="hostname",
)
def is_host_name(instance):
@@ -238,6 +249,7 @@ except ImportError: # pragma: no cover
else:
@_checks_drafts(
draft7="idn-hostname",
+ draft201909="idn-hostname",
draft202012="idn-hostname",
raises=(idna.IDNAError, UnicodeError),
)
@@ -265,6 +277,7 @@ except ImportError:
@_checks_drafts(
draft6="uri-reference",
draft7="uri-reference",
+ draft201909="uri-reference",
draft202012="uri-reference",
raises=ValueError,
)
@@ -276,6 +289,7 @@ except ImportError:
else:
@_checks_drafts(
draft7="iri",
+ draft201909="iri",
draft202012="iri",
raises=ValueError,
)
@@ -286,6 +300,7 @@ else:
@_checks_drafts(
draft7="iri-reference",
+ draft201909="iri-reference",
draft202012="iri-reference",
raises=ValueError,
)
@@ -294,10 +309,7 @@ else:
return True
return rfc3987.parse(instance, rule="IRI_reference")
- @_checks_drafts(
- name="uri",
- raises=ValueError,
- )
+ @_checks_drafts(name="uri", raises=ValueError)
def is_uri(instance):
if not isinstance(instance, str):
return True
@@ -306,6 +318,7 @@ else:
@_checks_drafts(
draft6="uri-reference",
draft7="uri-reference",
+ draft201909="uri-reference",
draft202012="uri-reference",
raises=ValueError,
)
@@ -332,6 +345,7 @@ if validate_rfc3339:
@_checks_drafts(
draft7="time",
+ draft201909="time",
draft202012="time",
)
def is_time(instance):
@@ -357,6 +371,7 @@ else:
@_checks_drafts(
draft3="date",
draft7="date",
+ draft201909="date",
draft202012="date",
raises=ValueError,
)
@@ -409,6 +424,7 @@ else:
@_checks_drafts(
draft6="json-pointer",
draft7="json-pointer",
+ draft201909="json-pointer",
draft202012="json-pointer",
raises=jsonpointer.JsonPointerException,
)
@@ -423,6 +439,7 @@ else:
# into a new external library.
@_checks_drafts(
draft7="relative-json-pointer",
+ draft201909="relative-json-pointer",
draft202012="relative-json-pointer",
raises=jsonpointer.JsonPointerException,
)
@@ -457,6 +474,7 @@ else:
@_checks_drafts(
draft6="uri-template",
draft7="uri-template",
+ draft201909="uri-template",
draft202012="uri-template",
)
def is_uri_template(instance):
@@ -471,6 +489,7 @@ except ImportError: # pragma: no cover
pass
else:
@_checks_drafts(
+ draft201909="duration",
draft202012="duration",
raises=isoduration.DurationParsingException,
)
@@ -481,6 +500,7 @@ else:
@_checks_drafts(
+ draft201909="uuid",
draft202012="uuid",
raises=ValueError,
)
diff --git a/jsonschema/_legacy_validators.py b/jsonschema/_legacy_validators.py
index 63adf49..88e7c33 100644
--- a/jsonschema/_legacy_validators.py
+++ b/jsonschema/_legacy_validators.py
@@ -106,7 +106,7 @@ def items_draft3_draft4(validator, items, instance, schema):
yield error
-def items_draft6_draft7(validator, items, instance, schema):
+def items_draft6_draft7_draft201909(validator, items, instance, schema):
if not validator.is_type(instance, "array"):
return
@@ -209,3 +209,19 @@ def contains_draft6_draft7(validator, contains, instance, schema):
yield ValidationError(
"None of %r are valid under the given schema" % (instance,),
)
+
+
+def recursiveRef(validator, recursiveRef, instance, schema):
+ scope_stack = validator.resolver.scopes_stack_copy
+ lookup_url, target = validator.resolver.resolution_scope, validator.schema
+
+ for each in reversed(scope_stack[1:]):
+ lookup_url, next_target = validator.resolver.resolve(each)
+ if next_target.get("$recursiveAnchor"):
+ target = next_target
+ else:
+ break
+
+ subschema = validator.resolver.resolve_local(recursiveRef, target)
+ for error in validator.descend(instance, subschema):
+ yield error
diff --git a/jsonschema/_types.py b/jsonschema/_types.py
index 3eab7b0..988fcca 100644
--- a/jsonschema/_types.py
+++ b/jsonschema/_types.py
@@ -185,4 +185,5 @@ draft6_type_checker = draft4_type_checker.redefine(
),
)
draft7_type_checker = draft6_type_checker
-draft202012_type_checker = draft7_type_checker
+draft201909_type_checker = draft7_type_checker
+draft202012_type_checker = draft201909_type_checker
diff --git a/jsonschema/_validators.py b/jsonschema/_validators.py
index 77063fa..d2f699f 100644
--- a/jsonschema/_validators.py
+++ b/jsonschema/_validators.py
@@ -342,35 +342,18 @@ def dynamicRef(validator, dynamicRef, instance, schema):
for url in scope_stack:
lookup_url = urljoin(url, dynamicRef)
- with validator.resolver.resolving(lookup_url) as lookup_schema:
- if ("$dynamicAnchor" in lookup_schema
- and fragment == lookup_schema["$dynamicAnchor"]):
- subschema = lookup_schema
+ with validator.resolver.resolving(lookup_url) as subschema:
+ if ("$dynamicAnchor" in subschema
+ and fragment == subschema["$dynamicAnchor"]):
for error in validator.descend(instance, subschema):
yield error
break
else:
- with validator.resolver.resolving(dynamicRef) as lookup_schema:
- subschema = lookup_schema
+ with validator.resolver.resolving(dynamicRef) as subschema:
for error in validator.descend(instance, subschema):
yield error
-def defs(validator, defs, instance, schema):
- if not validator.is_type(instance, "object"):
- return
-
- if '$defs' in instance:
- for definition, subschema in instance['$defs'].items():
- for error in validator.descend(
- subschema,
- schema,
- path=definition,
- schema_path=definition,
- ):
- yield error
-
-
def type(validator, types, instance, schema):
types = ensure_list(types)
diff --git a/jsonschema/schemas/draft2019-09.json b/jsonschema/schemas/draft2019-09.json
new file mode 100644
index 0000000..2248a0c
--- /dev/null
+++ b/jsonschema/schemas/draft2019-09.json
@@ -0,0 +1,42 @@
+{
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "$id": "https://json-schema.org/draft/2019-09/schema",
+ "$vocabulary": {
+ "https://json-schema.org/draft/2019-09/vocab/core": true,
+ "https://json-schema.org/draft/2019-09/vocab/applicator": true,
+ "https://json-schema.org/draft/2019-09/vocab/validation": true,
+ "https://json-schema.org/draft/2019-09/vocab/meta-data": true,
+ "https://json-schema.org/draft/2019-09/vocab/format": false,
+ "https://json-schema.org/draft/2019-09/vocab/content": true
+ },
+ "$recursiveAnchor": true,
+
+ "title": "Core and Validation specifications meta-schema",
+ "allOf": [
+ {"$ref": "meta/core"},
+ {"$ref": "meta/applicator"},
+ {"$ref": "meta/validation"},
+ {"$ref": "meta/meta-data"},
+ {"$ref": "meta/format"},
+ {"$ref": "meta/content"}
+ ],
+ "type": ["object", "boolean"],
+ "properties": {
+ "definitions": {
+ "$comment": "While no longer an official keyword as it is replaced by $defs, this keyword is retained in the meta-schema to prevent incompatible extensions as it remains in common use.",
+ "type": "object",
+ "additionalProperties": { "$recursiveRef": "#" },
+ "default": {}
+ },
+ "dependencies": {
+ "$comment": "\"dependencies\" is no longer a keyword, but schema authors should avoid redefining it to facilitate a smooth transition to \"dependentSchemas\" and \"dependentRequired\"",
+ "type": "object",
+ "additionalProperties": {
+ "anyOf": [
+ { "$recursiveRef": "#" },
+ { "$ref": "meta/validation#/$defs/stringArray" }
+ ]
+ }
+ }
+ }
+}
diff --git a/jsonschema/schemas/draft2019-09/applicator.json b/jsonschema/schemas/draft2019-09/applicator.json
new file mode 100644
index 0000000..24a1cc4
--- /dev/null
+++ b/jsonschema/schemas/draft2019-09/applicator.json
@@ -0,0 +1,56 @@
+{
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "$id": "https://json-schema.org/draft/2019-09/meta/applicator",
+ "$vocabulary": {
+ "https://json-schema.org/draft/2019-09/vocab/applicator": true
+ },
+ "$recursiveAnchor": true,
+
+ "title": "Applicator vocabulary meta-schema",
+ "type": ["object", "boolean"],
+ "properties": {
+ "additionalItems": { "$recursiveRef": "#" },
+ "unevaluatedItems": { "$recursiveRef": "#" },
+ "items": {
+ "anyOf": [
+ { "$recursiveRef": "#" },
+ { "$ref": "#/$defs/schemaArray" }
+ ]
+ },
+ "contains": { "$recursiveRef": "#" },
+ "additionalProperties": { "$recursiveRef": "#" },
+ "unevaluatedProperties": { "$recursiveRef": "#" },
+ "properties": {
+ "type": "object",
+ "additionalProperties": { "$recursiveRef": "#" },
+ "default": {}
+ },
+ "patternProperties": {
+ "type": "object",
+ "additionalProperties": { "$recursiveRef": "#" },
+ "propertyNames": { "format": "regex" },
+ "default": {}
+ },
+ "dependentSchemas": {
+ "type": "object",
+ "additionalProperties": {
+ "$recursiveRef": "#"
+ }
+ },
+ "propertyNames": { "$recursiveRef": "#" },
+ "if": { "$recursiveRef": "#" },
+ "then": { "$recursiveRef": "#" },
+ "else": { "$recursiveRef": "#" },
+ "allOf": { "$ref": "#/$defs/schemaArray" },
+ "anyOf": { "$ref": "#/$defs/schemaArray" },
+ "oneOf": { "$ref": "#/$defs/schemaArray" },
+ "not": { "$recursiveRef": "#" }
+ },
+ "$defs": {
+ "schemaArray": {
+ "type": "array",
+ "minItems": 1,
+ "items": { "$recursiveRef": "#" }
+ }
+ }
+}
diff --git a/jsonschema/schemas/draft2019-09/content.json b/jsonschema/schemas/draft2019-09/content.json
new file mode 100644
index 0000000..f6752a8
--- /dev/null
+++ b/jsonschema/schemas/draft2019-09/content.json
@@ -0,0 +1,17 @@
+{
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "$id": "https://json-schema.org/draft/2019-09/meta/content",
+ "$vocabulary": {
+ "https://json-schema.org/draft/2019-09/vocab/content": true
+ },
+ "$recursiveAnchor": true,
+
+ "title": "Content vocabulary meta-schema",
+
+ "type": ["object", "boolean"],
+ "properties": {
+ "contentMediaType": { "type": "string" },
+ "contentEncoding": { "type": "string" },
+ "contentSchema": { "$recursiveRef": "#" }
+ }
+}
diff --git a/jsonschema/schemas/draft2019-09/core.json b/jsonschema/schemas/draft2019-09/core.json
new file mode 100644
index 0000000..eb708a5
--- /dev/null
+++ b/jsonschema/schemas/draft2019-09/core.json
@@ -0,0 +1,57 @@
+{
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "$id": "https://json-schema.org/draft/2019-09/meta/core",
+ "$vocabulary": {
+ "https://json-schema.org/draft/2019-09/vocab/core": true
+ },
+ "$recursiveAnchor": true,
+
+ "title": "Core vocabulary meta-schema",
+ "type": ["object", "boolean"],
+ "properties": {
+ "$id": {
+ "type": "string",
+ "format": "uri-reference",
+ "$comment": "Non-empty fragments not allowed.",
+ "pattern": "^[^#]*#?$"
+ },
+ "$schema": {
+ "type": "string",
+ "format": "uri"
+ },
+ "$anchor": {
+ "type": "string",
+ "pattern": "^[A-Za-z][-A-Za-z0-9.:_]*$"
+ },
+ "$ref": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "$recursiveRef": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "$recursiveAnchor": {
+ "type": "boolean",
+ "default": false
+ },
+ "$vocabulary": {
+ "type": "object",
+ "propertyNames": {
+ "type": "string",
+ "format": "uri"
+ },
+ "additionalProperties": {
+ "type": "boolean"
+ }
+ },
+ "$comment": {
+ "type": "string"
+ },
+ "$defs": {
+ "type": "object",
+ "additionalProperties": { "$recursiveRef": "#" },
+ "default": {}
+ }
+ }
+}
diff --git a/jsonschema/schemas/draft2019-09/format.json b/jsonschema/schemas/draft2019-09/format.json
new file mode 100644
index 0000000..09bbfdd
--- /dev/null
+++ b/jsonschema/schemas/draft2019-09/format.json
@@ -0,0 +1,14 @@
+{
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "$id": "https://json-schema.org/draft/2019-09/meta/format",
+ "$vocabulary": {
+ "https://json-schema.org/draft/2019-09/vocab/format": true
+ },
+ "$recursiveAnchor": true,
+
+ "title": "Format vocabulary meta-schema",
+ "type": ["object", "boolean"],
+ "properties": {
+ "format": { "type": "string" }
+ }
+}
diff --git a/jsonschema/schemas/draft2019-09/hyper-schema.json b/jsonschema/schemas/draft2019-09/hyper-schema.json
new file mode 100644
index 0000000..3d23058
--- /dev/null
+++ b/jsonschema/schemas/draft2019-09/hyper-schema.json
@@ -0,0 +1,29 @@
+{
+ "$schema": "https://json-schema.org/draft/2019-09/hyper-schema",
+ "$id": "https://json-schema.org/draft/2019-09/meta/hyper-schema",
+ "$vocabulary": {
+ "https://json-schema.org/draft/2019-09/vocab/hyper-schema": true
+ },
+ "$recursiveAnchor": true,
+
+ "title": "JSON Hyper-Schema Vocabulary Schema",
+ "type": ["object", "boolean"],
+ "properties": {
+ "base": {
+ "type": "string",
+ "format": "uri-template"
+ },
+ "links": {
+ "type": "array",
+ "items": {
+ "$ref": "https://json-schema.org/draft/2019-09/links"
+ }
+ }
+ },
+ "links": [
+ {
+ "rel": "self",
+ "href": "{+%24id}"
+ }
+ ]
+}
diff --git a/jsonschema/schemas/draft2019-09/meta-data.json b/jsonschema/schemas/draft2019-09/meta-data.json
new file mode 100644
index 0000000..da04cff
--- /dev/null
+++ b/jsonschema/schemas/draft2019-09/meta-data.json
@@ -0,0 +1,37 @@
+{
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "$id": "https://json-schema.org/draft/2019-09/meta/meta-data",
+ "$vocabulary": {
+ "https://json-schema.org/draft/2019-09/vocab/meta-data": true
+ },
+ "$recursiveAnchor": true,
+
+ "title": "Meta-data vocabulary meta-schema",
+
+ "type": ["object", "boolean"],
+ "properties": {
+ "title": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "default": true,
+ "deprecated": {
+ "type": "boolean",
+ "default": false
+ },
+ "readOnly": {
+ "type": "boolean",
+ "default": false
+ },
+ "writeOnly": {
+ "type": "boolean",
+ "default": false
+ },
+ "examples": {
+ "type": "array",
+ "items": true
+ }
+ }
+}
diff --git a/jsonschema/schemas/draft2019-09/validation.json b/jsonschema/schemas/draft2019-09/validation.json
new file mode 100644
index 0000000..9f59677
--- /dev/null
+++ b/jsonschema/schemas/draft2019-09/validation.json
@@ -0,0 +1,98 @@
+{
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "$id": "https://json-schema.org/draft/2019-09/meta/validation",
+ "$vocabulary": {
+ "https://json-schema.org/draft/2019-09/vocab/validation": true
+ },
+ "$recursiveAnchor": true,
+
+ "title": "Validation vocabulary meta-schema",
+ "type": ["object", "boolean"],
+ "properties": {
+ "multipleOf": {
+ "type": "number",
+ "exclusiveMinimum": 0
+ },
+ "maximum": {
+ "type": "number"
+ },
+ "exclusiveMaximum": {
+ "type": "number"
+ },
+ "minimum": {
+ "type": "number"
+ },
+ "exclusiveMinimum": {
+ "type": "number"
+ },
+ "maxLength": { "$ref": "#/$defs/nonNegativeInteger" },
+ "minLength": { "$ref": "#/$defs/nonNegativeIntegerDefault0" },
+ "pattern": {
+ "type": "string",
+ "format": "regex"
+ },
+ "maxItems": { "$ref": "#/$defs/nonNegativeInteger" },
+ "minItems": { "$ref": "#/$defs/nonNegativeIntegerDefault0" },
+ "uniqueItems": {
+ "type": "boolean",
+ "default": false
+ },
+ "maxContains": { "$ref": "#/$defs/nonNegativeInteger" },
+ "minContains": {
+ "$ref": "#/$defs/nonNegativeInteger",
+ "default": 1
+ },
+ "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" },
+ "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" },
+ "required": { "$ref": "#/$defs/stringArray" },
+ "dependentRequired": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/stringArray"
+ }
+ },
+ "const": true,
+ "enum": {
+ "type": "array",
+ "items": true
+ },
+ "type": {
+ "anyOf": [
+ { "$ref": "#/$defs/simpleTypes" },
+ {
+ "type": "array",
+ "items": { "$ref": "#/$defs/simpleTypes" },
+ "minItems": 1,
+ "uniqueItems": true
+ }
+ ]
+ }
+ },
+ "$defs": {
+ "nonNegativeInteger": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "nonNegativeIntegerDefault0": {
+ "$ref": "#/$defs/nonNegativeInteger",
+ "default": 0
+ },
+ "simpleTypes": {
+ "enum": [
+ "array",
+ "boolean",
+ "integer",
+ "null",
+ "number",
+ "object",
+ "string"
+ ]
+ },
+ "stringArray": {
+ "type": "array",
+ "items": { "type": "string" },
+ "uniqueItems": true,
+ "default": []
+ }
+ }
+}
diff --git a/jsonschema/tests/test_jsonschema_test_suite.py b/jsonschema/tests/test_jsonschema_test_suite.py
index c0ddddd..22dab75 100644
--- a/jsonschema/tests/test_jsonschema_test_suite.py
+++ b/jsonschema/tests/test_jsonschema_test_suite.py
@@ -13,11 +13,13 @@ from jsonschema import (
Draft4Validator,
Draft6Validator,
Draft7Validator,
+ Draft201909Validator,
Draft202012Validator,
draft3_format_checker,
draft4_format_checker,
draft6_format_checker,
draft7_format_checker,
+ draft201909_format_checker,
draft202012_format_checker,
)
from jsonschema.tests._helpers import bug
@@ -28,6 +30,7 @@ DRAFT3 = SUITE.version(name="draft3")
DRAFT4 = SUITE.version(name="draft4")
DRAFT6 = SUITE.version(name="draft6")
DRAFT7 = SUITE.version(name="draft7")
+DRAFT201909 = SUITE.version(name="draft2019-09")
DRAFT202012 = SUITE.version(name="draft2020-12")
@@ -403,6 +406,41 @@ TestDraft7 = DRAFT7.to_unittest_testcase(
)
+TestDraft201909 = DRAFT201909.to_unittest_testcase(
+ DRAFT201909.tests(),
+ DRAFT201909.optional_tests_of(name="bignum"),
+ DRAFT201909.optional_tests_of(name="float-overflow"),
+ DRAFT201909.optional_tests_of(name="non-bmp-regex"),
+ DRAFT201909.optional_tests_of(name="refOfUnknownKeyword"),
+ Validator=Draft201909Validator,
+ skip=lambda test: (
+ skip(
+ message="unevaluatedItems is different in 2019-09 (needs work).",
+ subject="unevaluatedItems",
+ )(test)
+ or skip(
+ message="dynamicRef support isn't working yet.",
+ subject="recursiveRef",
+ )(test)
+ ),
+)
+
+
+TestDraft201909Format = DRAFT201909.to_unittest_testcase(
+ DRAFT201909.format_tests(),
+ Validator=Draft201909Validator,
+ format_checker=draft201909_format_checker,
+ skip=lambda test: (
+ complex_email_validation(test)
+ or missing_date_fromisoformat(test)
+ or allowed_leading_zeros(test)
+ or leap_second(test)
+ or missing_format(draft201909_format_checker)(test)
+ or complex_email_validation(test)
+ ),
+)
+
+
TestDraft202012 = DRAFT202012.to_unittest_testcase(
DRAFT202012.tests(),
DRAFT202012.optional_tests_of(name="bignum"),
diff --git a/jsonschema/validators.py b/jsonschema/validators.py
index 3c28b8d..295cf6f 100644
--- a/jsonschema/validators.py
+++ b/jsonschema/validators.py
@@ -145,12 +145,7 @@ def create(
TYPE_CHECKER = type_checker
ID_OF = staticmethod(id_of)
- def __init__(
- self,
- schema,
- resolver=None,
- format_checker=None,
- ):
+ def __init__(self, schema, resolver=None, format_checker=None):
if resolver is None:
resolver = RefResolver.from_schema(schema, id_of=id_of)
@@ -385,7 +380,7 @@ Draft6Validator = create(
"exclusiveMaximum": _validators.exclusiveMaximum,
"exclusiveMinimum": _validators.exclusiveMinimum,
"format": _validators.format,
- "items": _legacy_validators.items_draft6_draft7,
+ "items": _legacy_validators.items_draft6_draft7_draft201909,
"maxItems": _validators.maxItems,
"maxLength": _validators.maxLength,
"maxProperties": _validators.maxProperties,
@@ -426,7 +421,7 @@ Draft7Validator = create(
"exclusiveMinimum": _validators.exclusiveMinimum,
"format": _validators.format,
"if": _validators.if_,
- "items": _legacy_validators.items_draft6_draft7,
+ "items": _legacy_validators.items_draft6_draft7_draft201909,
"maxItems": _validators.maxItems,
"maxLength": _validators.maxLength,
"maxProperties": _validators.maxProperties,
@@ -451,6 +446,51 @@ Draft7Validator = create(
applicable_validators=_legacy_validators.ignore_ref_siblings,
)
+Draft201909Validator = create(
+ meta_schema=_utils.load_schema("draft2019-09"),
+ vocabulary_schemas=_utils.load_vocabulary("draft2019-09"),
+ validators={
+ "$ref": _validators.ref,
+ "$recursiveRef": _legacy_validators.recursiveRef,
+ "additionalItems": _validators.additionalItems,
+ "additionalProperties": _validators.additionalProperties,
+ "allOf": _validators.allOf,
+ "anyOf": _validators.anyOf,
+ "const": _validators.const,
+ "contains": _validators.contains,
+ "dependentRequired": _validators.dependentRequired,
+ "dependentSchemas": _validators.dependentSchemas,
+ "enum": _validators.enum,
+ "exclusiveMaximum": _validators.exclusiveMaximum,
+ "exclusiveMinimum": _validators.exclusiveMinimum,
+ "format": _validators.format,
+ "if": _validators.if_,
+ "items": _legacy_validators.items_draft6_draft7_draft201909,
+ "maxItems": _validators.maxItems,
+ "maxLength": _validators.maxLength,
+ "maxProperties": _validators.maxProperties,
+ "maximum": _validators.maximum,
+ "minItems": _validators.minItems,
+ "minLength": _validators.minLength,
+ "minProperties": _validators.minProperties,
+ "minimum": _validators.minimum,
+ "multipleOf": _validators.multipleOf,
+ "not": _validators.not_,
+ "oneOf": _validators.oneOf,
+ "pattern": _validators.pattern,
+ "patternProperties": _validators.patternProperties,
+ "properties": _validators.properties,
+ "propertyNames": _validators.propertyNames,
+ "required": _validators.required,
+ "type": _validators.type,
+ "unevaluatedItems": _validators.unevaluatedItems,
+ "unevaluatedProperties": _validators.unevaluatedProperties,
+ "uniqueItems": _validators.uniqueItems,
+ },
+ type_checker=_types.draft201909_type_checker,
+ version="draft2019-09",
+)
+
Draft202012Validator = create(
meta_schema=_utils.load_schema("draft2020-12"),
vocabulary_schemas=_utils.load_vocabulary("draft2020-12"),