diff options
author | Julian Berman <Julian@GrayVines.com> | 2019-08-04 18:57:26 -0400 |
---|---|---|
committer | Julian Berman <Julian@GrayVines.com> | 2019-08-04 18:57:26 -0400 |
commit | cab27b8f1515536e7fb030ea4d3a2ce2713d0498 (patch) | |
tree | f3da45d47915e70a9ab79f76a62cc3dfe11d2687 | |
parent | 918dad5989736e2d40cffe85556bc87935dbfb35 (diff) | |
download | jsonschema-protocol.tar.gz |
WIPprotocol
-rw-r--r-- | README.rst | 2 | ||||
-rw-r--r-- | docs/errors.rst | 2 | ||||
-rw-r--r-- | docs/faq.rst | 13 | ||||
-rw-r--r-- | docs/spelling-wordlist.txt | 1 | ||||
-rw-r--r-- | docs/validate.rst | 158 | ||||
-rw-r--r-- | jsonschema/_protocol.py | 135 | ||||
-rw-r--r-- | jsonschema/_types.py | 5 | ||||
-rw-r--r-- | jsonschema/tests/test_validators.py | 8 | ||||
-rw-r--r-- | jsonschema/validators.py | 21 | ||||
-rw-r--r-- | test-requirements.txt | 1 |
10 files changed, 187 insertions, 159 deletions
@@ -71,7 +71,7 @@ Features and `Draft 3 <https://python-jsonschema.readthedocs.io/en/latest/validate/#jsonschema.Draft3Validator>`_ -* `Lazy validation <https://python-jsonschema.readthedocs.io/en/latest/validate/#jsonschema.IValidator.iter_errors>`_ +* `Lazy validation <https://python-jsonschema.readthedocs.io/en/latest/validate/#jsonschema.validators.ValidatorProtocol.iter_errors>`_ that can iteratively report *all* validation errors. * `Programmatic querying <https://python-jsonschema.readthedocs.io/en/latest/errors/#module-jsonschema>`_ diff --git a/docs/errors.rst b/docs/errors.rst index 1851ff5..e892777 100644 --- a/docs/errors.rst +++ b/docs/errors.rst @@ -272,7 +272,7 @@ error objects. As you can see, `jsonschema.exceptions.ErrorTree` takes an iterable of `ValidationError`\s when constructing a tree so you can directly pass it the return value of a validator object's -`jsonschema.IValidator.iter_errors` method. +`jsonschema.validators.ValidatorProtocol.iter_errors` method. `ErrorTree`\s support a number of useful operations. The first one we might want to perform is to check whether a given element in our instance diff --git a/docs/faq.rst b/docs/faq.rst index 889b306..33fa293 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -16,12 +16,13 @@ It's perfectly valid (and perhaps even useful) to have a default that is not valid under the schema it lives in! So an instance modified by the default would pass validation the first time, but fail the second! -Still, filling in defaults is a thing that is useful. `jsonschema` allows -you to `define your own validator classes and callables <creating>`, so you can -easily create an `jsonschema.IValidator` that does do default setting. Here's -some code to get you started. (In this code, we add the default properties to -each object *before* the properties are validated, so the default values -themselves will need to be valid under the schema.) +Still, filling in defaults is a thing that is useful. +`jsonschema` allows you to `define your own validator classes +and callables <creating>`, so you can easily create an +`jsonschema.validators.ValidatorProtocol` that does do default setting. +Here's some code to get you started. (In this code, we add the default +properties to each object *before* the properties are validated, so the +default values themselves will need to be valid under the schema.) .. code-block:: python diff --git a/docs/spelling-wordlist.txt b/docs/spelling-wordlist.txt index e43b09c..8dfaff9 100644 --- a/docs/spelling-wordlist.txt +++ b/docs/spelling-wordlist.txt @@ -1,5 +1,4 @@ # this appears to be misinterpreting Napoleon types as prose, sigh... -IValidator TypeChecker UnknownType ValidationError diff --git a/docs/validate.rst b/docs/validate.rst index 5a4448d..726bb0e 100644 --- a/docs/validate.rst +++ b/docs/validate.rst @@ -26,130 +26,7 @@ The Validator Interface `jsonschema` defines an (informal) interface that all validator classes should adhere to. -.. class:: IValidator(schema, types=(), resolver=None, format_checker=None) - - :argument dict schema: the schema that the validator object - will validate with. It is assumed to be valid, and providing - an invalid schema can lead to undefined behavior. See - `IValidator.check_schema` to validate a schema first. - :argument resolver: an instance of `RefResolver` that will be - used to resolve :validator:`$ref` properties (JSON references). If - unprovided, one will be created. - :argument format_checker: an instance of `FormatChecker` - whose `FormatChecker.conforms` method will be called to - check and see if instances conform to each :validator:`format` - property present in the schema. If unprovided, no validation - will be done for :validator:`format`. Certain formats require - additional packages to be installed (ipv5, uri, color, date-time). - The required packages can be found at the bottom of this page. - :argument types: - .. deprecated:: 3.0.0 - - Use `TypeChecker.redefine` and - `jsonschema.validators.extend` instead of this argument. - - See `validating-types` for details. - - If used, this overrides or extends the list of known types when - validating the :validator:`type` property. - - What is provided should map strings (type names) to class objects - that will be checked via `isinstance`. - - - .. attribute:: META_SCHEMA - - An object representing the validator's meta schema (the schema that - describes valid schemas in the given version). - - .. attribute:: VALIDATORS - - A mapping of validator names (`str`\s) to functions - that validate the validator property with that name. For more - information see `creating-validators`. - - .. attribute:: TYPE_CHECKER - - A `TypeChecker` that will be used when validating :validator:`type` - properties in JSON schemas. - - .. attribute:: schema - - The schema that was passed in when initializing the object. - - .. attribute:: DEFAULT_TYPES - - .. deprecated:: 3.0.0 - - Use of this attribute is deprecated in favor of the new `type - checkers <TypeChecker>`. - - See `validating-types` for details. - - For backwards compatibility on existing validator classes, a mapping of - JSON types to Python class objects which define the Python types for - each JSON type. - - Any existing code using this attribute should likely transition to - using `TypeChecker.is_type`. - - - .. classmethod:: check_schema(schema) - - Validate the given schema against the validator's `META_SCHEMA`. - - :raises: `jsonschema.exceptions.SchemaError` if the schema - is invalid - - .. method:: is_type(instance, type) - - Check if the instance is of the given (JSON Schema) type. - - :type type: str - :rtype: bool - :raises: `jsonschema.exceptions.UnknownType` if ``type`` - is not a known type. - - .. method:: is_valid(instance) - - Check if the instance is valid under the current `schema`. - - :rtype: bool - - >>> schema = {"maxItems" : 2} - >>> Draft3Validator(schema).is_valid([2, 3, 4]) - False - - .. method:: iter_errors(instance) - - Lazily yield each of the validation errors in the given instance. - - :rtype: an `collections.Iterable` of - `jsonschema.exceptions.ValidationError`\s - - >>> schema = { - ... "type" : "array", - ... "items" : {"enum" : [1, 2, 3]}, - ... "maxItems" : 2, - ... } - >>> v = Draft3Validator(schema) - >>> for error in sorted(v.iter_errors([2, 3, 4]), key=str): - ... print(error.message) - 4 is not one of [1, 2, 3] - [2, 3, 4] is too long - - .. method:: validate(instance) - - Check if the instance is valid under the current `schema`. - - :raises: `jsonschema.exceptions.ValidationError` if the - instance is invalid - - >>> schema = {"maxItems" : 2} - >>> Draft3Validator(schema).validate([2, 3, 4]) - Traceback (most recent call last): - ... - ValidationError: [2, 3, 4] is too long +.. autoclass:: jsonschema.validators.ValidatorProtocol All of the `versioned validators <versioned-validators>` that are included with @@ -160,12 +37,13 @@ more information see `creating-validators`. Type Checking ------------- -To handle JSON Schema's :validator:`type` property, a `IValidator` uses -an associated `TypeChecker`. The type checker provides an immutable -mapping between names of types and functions that can test if an instance is -of that type. The defaults are suitable for most users - each of the -`versioned validators <versioned-validators>` that are included with -`jsonschema` have a `TypeChecker` that can correctly handle their respective +To handle JSON Schema's :validator:`type` property, a +`jsonschema.validators.ValidatorProtocol` uses an associated +`TypeChecker`. The type checker provides an immutable mapping between +names of types and functions that can test if an instance is of that +type. The defaults are suitable for most users - each of the `versioned +validators <versioned-validators>` that are included with `jsonschema` +have a `TypeChecker` that can correctly handle their respective versions. .. seealso:: `validating-types` @@ -201,10 +79,11 @@ particular `int`\s and `float`\s, along with more general instance checks can introduce significant slowdown, especially given how common validating these types are. -If you *do* want the generality, or just want to add a few specific additional -types as being acceptable for a validator object, then you should update an -existing `TypeChecker` or create a new one. You may then create a new -`IValidator` via `jsonschema.validators.extend`. +If you *do* want the generality, or just want to add a few specific +additional types as being acceptable for a validator object, then +you should update an existing `TypeChecker` or create a new one. You +may then create a new `jsonschema.validators.ValidatorProtocol` via +`jsonschema.validators.extend`. .. code-block:: python @@ -230,10 +109,11 @@ existing `TypeChecker` or create a new one. You may then create a new Versioned Validators -------------------- -`jsonschema` ships with validator classes for various versions of -the JSON Schema specification. For details on the methods and attributes -that each validator class provides see the `IValidator` interface, -which each included validator class implements. +`jsonschema` ships with validator classes for various versions +of the JSON Schema specification. For details on the methods +and attributes that each validator class provides see the +`jsonschema.validators.ValidatorProtocol` protocol, which each included +validator class implements. .. autoclass:: Draft7Validator @@ -271,7 +151,7 @@ JSON Schema defines the :validator:`format` property which can be used to check if primitive types (``string``\s, ``number``\s, ``boolean``\s) conform to well-defined formats. By default, no validation is enforced, but optionally, validation can be enabled by hooking in a format-checking object into an -`IValidator`. +`jsonschema.validators.ValidatorProtocol`. .. doctest:: diff --git a/jsonschema/_protocol.py b/jsonschema/_protocol.py new file mode 100644 index 0000000..86106a8 --- /dev/null +++ b/jsonschema/_protocol.py @@ -0,0 +1,135 @@ +try: + from typing import Protocol +except ImportError: + Protocol = object + + +class ValidatorProtocol(Protocol): + def iter_errors(self): + pass + +# (schema, types=(), resolver=None, format_checker=None) + # + # :argument dict schema: the schema that the validator object + # will validate with. It is assumed to be valid, and providing + # an invalid schema can lead to undefined behavior. See + # `jsonschema.validators.ValidatorProtocol.check_schema` to + # validate a schema first. + # :argument resolver: an instance of `RefResolver` that will be + # used to resolve :validator:`$ref` properties (JSON references). If + # unprovided, one will be created. + # :argument format_checker: an instance of `FormatChecker` + # whose `FormatChecker.conforms` method will be called to + # check and see if instances conform to each :validator:`format` + # property present in the schema. If unprovided, no validation + # will be done for :validator:`format`. Certain formats require + # additional packages to be installed (ipv5, uri, color, date-time). + # The required packages can be found at the bottom of this page. + # :argument types: + # .. deprecated:: 3.0.0 + # + # Use `TypeChecker.redefine` and + # `jsonschema.validators.extend` instead of this argument. + # + # See `validating-types` for details. + # + # If used, this overrides or extends the list of known types when + # validating the :validator:`type` property. + # + # What is provided should map strings (type names) to class objects + # that will be checked via `isinstance`. + # + # + # .. attribute:: META_SCHEMA + # + # An object representing the validator's meta schema (the schema that + # describes valid schemas in the given version). + # + # .. attribute:: VALIDATORS + # + # A mapping of validator names (`str`\s) to functions + # that validate the validator property with that name. For more + # information see `creating-validators`. + # + # .. attribute:: TYPE_CHECKER + # + # A `TypeChecker` that will be used when validating :validator:`type` + # properties in JSON schemas. + # + # .. attribute:: schema + # + # The schema that was passed in when initializing the object. + # + # .. attribute:: DEFAULT_TYPES + # + # .. deprecated:: 3.0.0 + # + # Use of this attribute is deprecated in favor of the new `type + # checkers <TypeChecker>`. + # + # See `validating-types` for details. + # + # For backwards compatibility on existing validator classes, a mapping of + # JSON types to Python class objects which define the Python types for + # each JSON type. + # + # Any existing code using this attribute should likely transition to + # using `TypeChecker.is_type`. + # + # + # .. classmethod:: check_schema(schema) + # + # Validate the given schema against the validator's `META_SCHEMA`. + # + # :raises: `jsonschema.exceptions.SchemaError` if the schema + # is invalid + # + # .. method:: is_type(instance, type) + # + # Check if the instance is of the given (JSON Schema) type. + # + # :type type: str + # :rtype: bool + # :raises: `jsonschema.exceptions.UnknownType` if ``type`` + # is not a known type. + # + # .. method:: is_valid(instance) + # + # Check if the instance is valid under the current `schema`. + # + # :rtype: bool + # + # >>> schema = {"maxItems" : 2} + # >>> Draft3Validator(schema).is_valid([2, 3, 4]) + # False + # + # .. method:: iter_errors(instance) + # + # Lazily yield each of the validation errors in the given instance. + # + # :rtype: an `collections.Iterable` of + # `jsonschema.exceptions.ValidationError`\s + # + # >>> schema = { + # ... "type" : "array", + # ... "items" : {"enum" : [1, 2, 3]}, + # ... "maxItems" : 2, + # ... } + # >>> v = Draft3Validator(schema) + # >>> for error in sorted(v.iter_errors([2, 3, 4]), key=str): + # ... print(error.message) + # 4 is not one of [1, 2, 3] + # [2, 3, 4] is too long + # + # .. method:: validate(instance) + # + # Check if the instance is valid under the current `schema`. + # + # :raises: `jsonschema.exceptions.ValidationError` if the + # instance is invalid + # + # >>> schema = {"maxItems" : 2} + # >>> Draft3Validator(schema).validate([2, 3, 4]) + # Traceback (most recent call last): + # ... + # ValidationError: [2, 3, 4] is too long diff --git a/jsonschema/_types.py b/jsonschema/_types.py index a71a4e3..b79d1df 100644 --- a/jsonschema/_types.py +++ b/jsonschema/_types.py @@ -50,8 +50,9 @@ class TypeChecker(object): """ A ``type`` property checker. - A `TypeChecker` performs type checking for an `IValidator`. Type - checks to perform are updated using `TypeChecker.redefine` or + A `TypeChecker` performs type checking for an + `jsonschema.validators.ValidatorProtocol`. Type checks + to perform are updated using `TypeChecker.redefine` or `TypeChecker.redefine_many` and removed via `TypeChecker.remove`. Each of these return a new `TypeChecker` object. diff --git a/jsonschema/tests/test_validators.py b/jsonschema/tests/test_validators.py index e4572c5..e5a6677 100644 --- a/jsonschema/tests/test_validators.py +++ b/jsonschema/tests/test_validators.py @@ -7,6 +7,7 @@ import json import os import sys import tempfile +import typing import unittest from twisted.trial.unittest import SynchronousTestCase @@ -176,6 +177,13 @@ class TestCreateAndExtend(SynchronousTestCase): Derived = validators.extend(Original) self.assertEqual(Derived.ID_OF(Derived.META_SCHEMA), correct_id) + def test_create_produces_something_ValidatorProtocol_compliant(self): + Validator = validators.create(meta_schema={}, validators=()) + self.assertIsInstance( + Validator({}), + typing.runtime_checkable(validators.ValidatorProtocol), + ) + class TestLegacyTypeChecking(SynchronousTestCase): def test_create_default_types(self): diff --git a/jsonschema/validators.py b/jsonschema/validators.py index e1ea871..a06c936 100644 --- a/jsonschema/validators.py +++ b/jsonschema/validators.py @@ -14,6 +14,7 @@ from jsonschema import ( _validators, exceptions, ) +from jsonschema._protocol import ValidatorProtocol from jsonschema.compat import ( Sequence, int_types, @@ -214,7 +215,7 @@ def create( Returns: - a new `jsonschema.IValidator` class + a new `ValidatorProtocol` class """ if default_types is not None: @@ -372,7 +373,7 @@ def extend(validator, validators=(), version=None, type_checker=None): Arguments: - validator (jsonschema.IValidator): + validator (ValidatorProtocol): an existing validator class @@ -402,11 +403,12 @@ def extend(validator, validators=(), version=None, type_checker=None): a type checker, used when applying the :validator:`type` validator. If unprovided, the type checker of the extended - `jsonschema.IValidator` will be carried along.` + `ValidatorProtocol` will be carried along.` Returns: - a new `jsonschema.IValidator` class extending the one provided + a new `jsonschema.validators.ValidatorProtocol`-implementing + class extending the one provided .. note:: Meta Schemas @@ -848,10 +850,11 @@ def validate(instance, schema, cls=None, *args, **kwargs): valid, since not doing so can lead to less obvious error messages and fail in less obvious or consistent ways. - If you know you have a valid schema already, especially if you - intend to validate multiple instances with the same schema, you - likely would prefer using the `IValidator.validate` method directly - on a specific validator (e.g. ``Draft7Validator.validate``). + If you know you have a valid schema already, especially + if you intend to validate multiple instances with + the same schema, you likely would prefer using the + `ValidatorProtocol.validate` method directly on a specific validator + (e.g. ``Draft7Validator.validate``). Arguments: @@ -864,7 +867,7 @@ def validate(instance, schema, cls=None, *args, **kwargs): The schema to validate with - cls (IValidator): + cls (jsonschema.validators.ValidatorProtocol): The class that will be used to validate the instance. diff --git a/test-requirements.txt b/test-requirements.txt index 082785c..9ecacd2 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1 +1,2 @@ +typing; python_version == '2.7' Twisted |