summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorJulian Berman <Julian@GrayVines.com>2013-04-17 23:39:52 -0400
committerJulian Berman <Julian@GrayVines.com>2013-04-17 23:41:11 -0400
commitac9b9c624e8dcb3ee41f6cbf40dc4260e1770054 (patch)
treed9153ab959c8b13a3f6ca3fda8756f100efdf981 /docs
parentcc09cafc1d357c4a5f05efc023055bae5f396bc2 (diff)
downloadjsonschema-ac9b9c624e8dcb3ee41f6cbf40dc4260e1770054.tar.gz
Add a JSON Schema documentation role.
Diffstat (limited to 'docs')
-rw-r--r--docs/conf.py5
-rw-r--r--docs/creating.rst5
-rw-r--r--docs/doc-requirements.txt1
-rw-r--r--docs/errors.rst56
-rw-r--r--docs/jsonschema_role.py111
-rw-r--r--docs/validate.rst88
6 files changed, 194 insertions, 72 deletions
diff --git a/docs/conf.py b/docs/conf.py
index b0ca102..cce3f2f 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -23,8 +23,11 @@ extensions = [
'sphinx.ext.doctest',
'sphinx.ext.intersphinx',
'sphinx.ext.viewcode',
+ 'jsonschema_role',
]
+cache_path = "_cache"
+
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -58,7 +61,7 @@ version = release.partition("-")[0]
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
-exclude_patterns = ['_build']
+exclude_patterns = ['_build', "_cache", "_static", "_templates"]
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
diff --git a/docs/creating.rst b/docs/creating.rst
index 330dc4c..fc498a1 100644
--- a/docs/creating.rst
+++ b/docs/creating.rst
@@ -17,5 +17,6 @@ Creating Validation Errors
Any validating function that validates against a subschema should call
:meth:`ValidatorMixin.descend`, rather than :meth:`ValidatorMixin.iter_errors`.
If it recurses into the instance, or schema, it should pass one or both of the
-``path`` or ``schema_path`` arguments to ``descend`` in order to properly
-maintain where in the instance or schema respsectively the error occurred.
+``path`` or ``schema_path`` arguments to :meth:`ValidatorMixin.descend` in
+order to properly maintain where in the instance or schema respsectively the
+error occurred.
diff --git a/docs/doc-requirements.txt b/docs/doc-requirements.txt
new file mode 100644
index 0000000..ab90481
--- /dev/null
+++ b/docs/doc-requirements.txt
@@ -0,0 +1 @@
+lxml
diff --git a/docs/errors.rst b/docs/errors.rst
index 1d8ab97..6d3a457 100644
--- a/docs/errors.rst
+++ b/docs/errors.rst
@@ -17,7 +17,8 @@ raised or returned, depending on which method or function is used.
.. attribute:: validator
- The failed validator.
+ The failed `validator
+ <http://json-schema.org/latest/json-schema-validation.html#anchor12>`_.
.. attribute:: validator_value
@@ -27,7 +28,7 @@ raised or returned, depending on which method or function is used.
The full schema that this error came from. This is potentially a
subschema from within the schema that was passed into the validator, or
- even an entirely different schema if a ``$ref`` was followed.
+ even an entirely different schema if a :validator:`$ref` was followed.
.. attribute:: schema_path
@@ -53,8 +54,8 @@ raised or returned, depending on which method or function is used.
If the error was caused by errors in subschemas, the list of errors
from the subschemas will be available on this property. The
- ``schema_path`` and ``path`` of these errors will be relative to the
- parent error.
+ :attr:`.schema_path` and :attr:`.path` of these errors will be relative
+ to the parent error.
.. attribute:: cause
@@ -99,9 +100,9 @@ The error messages in this situation are not very helpful on their own:
The instance is not valid under any of the given schemas
The instance is not valid under any of the given schemas
-If we look at :attr:`ValidationError.path` on each of the errors, we can find
+If we look at :attr:`~ValidationError.path` on each of the errors, we can find
out which elements in the instance correspond to each of the errors. In
-this example, :attr:`ValidationError.path` will have only one element, which
+this example, :attr:`~ValidationError.path` will have only one element, which
will be the index in our list.
.. code-block:: python
@@ -114,16 +115,16 @@ will be the index in our list.
Since our schema contained nested subschemas, it can be helpful to look at
the specific part of the instance and subschema that caused each of the errors.
-This can be seen with the :attr:`ValidationError.instance` and
-:attr:`ValidationError.schema` attributes.
+This can be seen with the :attr:`~ValidationError.instance` and
+:attr:`~ValidationError.schema` attributes.
-With validators like ``anyOf``, the :attr:`ValidationError.context` attribute
-can be used to see the sub-errors which caused the failure. Since these errors
-actually came from two separate subschemas, it can be helpful to look at the
-:attr:`ValidationError.schema_path` attribute as well to see where exactly in
-the schema each of these errors come from. In the case of sub-errors from the
-:attr:`ValidationError.context` attribute, this path will be relative to the
-:attr:`ValidationError.schema_path` of the parent error.
+With validators like :validator:`anyOf`, the :attr:`~ValidationError.context`
+attribute can be used to see the sub-errors which caused the failure. Since
+these errors actually came from two separate subschemas, it can be helpful to
+look at the :attr:`~ValidationError.schema_path` attribute as well to see where
+exactly in the schema each of these errors come from. In the case of sub-errors
+from the :attr:`~ValidationError.context` attribute, this path will be relative
+to the :attr:`~ValidationError.schema_path` of the parent error.
.. code-block:: python
@@ -180,11 +181,11 @@ more easily than by just iterating over the error objects.
As you can see, :class:`ErrorTree` takes an iterable of
:class:`ValidationError`\s when constructing a tree so you can directly pass it
-the return value of a validator's ``iter_errors`` method.
+the return value of a validator's :attr:`~IValidator.iter_errors` method.
:class:`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
-failed validation. We do so using the ``in`` operator:
+failed validation. We do so using the :keyword:`in` operator:
.. code-block:: python
@@ -199,16 +200,17 @@ did have an error (in fact it had 2), while the 1th index (``2``) did not (i.e.
it was valid).
If we want to see which errors a child had, we index into the tree and look at
-the ``errors`` attribute.
+the :attr:`~ErrorTree.errors` attribute.
.. code-block:: python
>>> sorted(tree[0].errors)
['enum', 'type']
-Here we see that the ``enum`` and ``type`` validators failed for index 0. In
-fact ``errors`` is a dict, whose values are the :class:`ValidationError`\s, so
-we can get at those directly if we want them.
+Here we see that the :validator:`enum` and :validator:`type` validators failed
+for index ``0``. In fact :attr:`~ErrorTree.errors` is a dict, whose values are
+the :class:`ValidationError`\s, so we can get at those directly if we want
+them.
.. code-block:: python
@@ -216,7 +218,7 @@ we can get at those directly if we want them.
'spam' is not of type 'number'
Of course this means that if we want to know if a given validator failed for a
-given index, we check for its presence in ``errors``:
+given index, we check for its presence in :attr:`~ErrorTree.errors`:
.. code-block:: python
@@ -227,9 +229,9 @@ given index, we check for its presence in ``errors``:
False
Finally, if you were paying close enough attention, you'll notice that we
-haven't seen our ``minItems`` error appear anywhere yet. This is because
-``minItems`` is an error that applies globally to the instance itself. So it
-appears in the root node of the tree.
+haven't seen our :validator:`minItems` error appear anywhere yet. This is
+because :validator:`minItems` is an error that applies globally to the instance
+itself. So it appears in the root node of the tree.
.. code-block:: python
@@ -240,5 +242,5 @@ That's all you need to know to use error trees.
To summarize, each tree contains child trees that can be accessed by indexing
the tree to get the corresponding child tree for a given index into the
-instance. Each tree and child has a ``errors`` attribute, a dict, that maps the
-failed validator to the corresponding validation error.
+instance. Each tree and child has a :attr:`~ErrorTree.errors` attribute, a
+dict, that maps the failed validator to the corresponding validation error.
diff --git a/docs/jsonschema_role.py b/docs/jsonschema_role.py
new file mode 100644
index 0000000..03be12a
--- /dev/null
+++ b/docs/jsonschema_role.py
@@ -0,0 +1,111 @@
+from datetime import datetime
+from docutils import nodes
+import errno
+import os
+import urllib2
+
+from lxml import html
+
+
+VALIDATION_SPEC = "http://json-schema.org/latest/json-schema-validation.html"
+
+
+def setup(app):
+ """
+ Install the plugin.
+
+ :argument sphinx.application.Sphinx app: the Sphinx application context
+
+ """
+
+ app.add_config_value("cache_path", "_cache", "")
+
+ try:
+ os.makedirs(app.config.cache_path)
+ except OSError as error:
+ if error.errno != errno.EEXIST:
+ raise
+
+ path = os.path.join(app.config.cache_path, "spec.html")
+ spec = fetch_or_load(path)
+ app.add_role("validator", docutils_sucks(spec))
+
+
+def fetch_or_load(spec_path):
+ """
+ Fetch a new specification or use the cache if it's current.
+
+ :argument cache_path: the path to a cached specification
+
+ """
+
+ headers = {}
+
+ try:
+ modified = datetime.utcfromtimestamp(os.path.getmtime(spec_path))
+ date = modified.strftime("%a, %d %b %Y %I:%M:%S UTC")
+ headers["If-Modified-Since"] = date
+ except OSError as error:
+ if error.errno != errno.ENOENT:
+ raise
+
+ request = urllib2.Request(VALIDATION_SPEC, headers=headers)
+ response = urllib2.urlopen(request)
+
+ if response.code == 200:
+ with open(spec_path, "w+") as spec:
+ spec.writelines(response)
+ spec.seek(0)
+ return html.parse(spec)
+
+ with open(spec_path) as spec:
+ return html.parse(spec)
+
+
+def docutils_sucks(spec):
+ """
+ Yeah.
+
+ It doesn't allow using a class because it does stupid stuff like try to set
+ attributes on the callable object rather than just keeping a dict.
+
+ """
+
+ base_url = VALIDATION_SPEC
+
+ def validator(name, raw_text, text, lineno, inliner):
+ """
+ Link to the JSON Schema documentation for a validator.
+
+ :argument str name: the name of the role in the document
+ :argument str raw_source: the raw text (role with argument)
+ :argument str text: the argument given to the role
+ :argument int lineno: the line number
+ :argument docutils.parsers.rst.states.Inliner inliner: the inliner
+
+ :returns: 2-tuple of nodes to insert into the document and an iterable
+ of system messages, both possibly empty
+
+ """
+
+ header = spec.xpath(
+ "//h3[re:match(text(), '(^|\W){0}($|\W,)', 'i')]".format(text),
+ namespaces={"re": "http://exslt.org/regular-expressions"},
+ )
+
+ if len(header) == 0:
+ inliner.reporter.warning(
+ "Didn't find a target for {0}".format(text),
+ )
+ uri = base_url
+ else:
+ if len(header) > 1:
+ inliner.reporter.warning(
+ "Found multiple targets for {0}".format(text),
+ )
+ uri = base_url + "#" + header[0].getprevious().attrib["name"]
+
+ reference = nodes.reference(raw_text, text, refuri=uri)
+ return [reference], []
+
+ return validator
diff --git a/docs/validate.rst b/docs/validate.rst
index 4435286..6fe2b29 100644
--- a/docs/validate.rst
+++ b/docs/validate.rst
@@ -14,7 +14,7 @@ The simplest way to validate an instance under a given schema is to use the
.. autofunction:: validate
- Validate an ``instance`` under the given ``schema``.
+ Validate an instance under the given schema.
>>> validate([2, 3, 4], {"maxItems" : 2})
Traceback (most recent call last):
@@ -24,8 +24,9 @@ The simplest way to validate an instance under a given schema is to use the
:func:`validate` will first verify that the provided schema is itself
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 or don't care, you might prefer using the ``validate`` method
- directly on a specific validator (e.g. :meth:`Draft4Validator.validate`).
+ already or don't care, you might prefer using the
+ :meth:`~IValidator.validate` method directly on a specific validator
+ (e.g. :meth:`Draft4Validator.validate`).
:argument instance: the instance to validate
@@ -34,12 +35,12 @@ The simplest way to validate an instance under a given schema is to use the
the instance.
If the ``cls`` argument is not provided, two things will happen in
- accordance with the specification. First, if the ``schema`` has a
- ``$schema`` property containing a known meta-schema (known by a validator
- registered with :func:`validates`), then the proper validator will be used.
- The specification recommends that all schemas contain ``$schema``
- properties for this reason. If no ``$schema`` property is found, the
- default validator class is :class:`Draft4Validator`.
+ accordance with the specification. First, if the schema has a
+ :validator:`$schema` property containing a known meta-schema [#]_ then the
+ proper validator will be used. The specification recommends that all
+ schemas contain :validator:`$schema` properties for this reason. If no
+ :validator:`$schema` property is found, the default validator class is
+ :class:`Draft4Validator`.
Any other provided positional and keyword arguments will be passed on when
instantiating the ``cls``.
@@ -49,6 +50,9 @@ The simplest way to validate an instance under a given schema is to use the
:exc:`SchemaError` if the schema itself is invalid
+ .. rubric:: Footnotes
+ .. [#] known by a validator registered with :func:`validates`
+
The Validator Interface
-----------------------
@@ -64,25 +68,25 @@ adhere to.
:meth:`IValidator.check_schema` to validate a schema
first.
:argument types: Override or extend the list of known types when validating
- the ``type`` property. Should map strings (type names) to
- class objects that will be checked via ``isinstance``. See
- :ref:`validating-types` for details.
+ the :validator:`type` property. Should map strings (type
+ names) to class objects that will be checked via
+ :func:`isinstance`. See :ref:`validating-types` for
+ details.
:type types: dict or iterable of 2-tuples
:argument resolver: an instance of :class:`RefResolver` that will be used
- to resolve ``$ref`` properties (JSON references). If
- unprovided, one will be created.
- :argument format_checker: an object with a ``conform()`` method that will
- be called to check and see if instances conform
- to each ``format`` property present in the
+ to resolve :validator:`$ref` properties (JSON
+ references). If unprovided, one will be created.
+ :argument format_checker: an instance of :class:`FormatChecker` whose
+ :meth:`~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 ``format``. :class:`FormatChecker` is a
- concrete implementation of an object of this form
- that can be used for common formats.
+ for :validator:`format`.
.. attribute:: DEFAULT_TYPES
The default mapping of JSON types to Python types used when validating
- ``type`` properties in JSON schemas.
+ :validator:`type` properties in JSON schemas.
.. attribute:: META_SCHEMA
@@ -162,20 +166,21 @@ Validating With Additional Types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Occasionally it can be useful to provide additional or alternate types when
-validating the JSON Schema's ``type`` property. Validators allow this by taking
-a ``types`` argument on construction that specifies additional types, or which
-can be used to specify a different set of Python types to map to a given JSON
-type.
-
-``jsonschema`` tries to strike a balance between performance in the common case
-and generality. For instance, JSON defines a ``number`` type, which can be
-validated with a schema such as ``{"type" : "number"}``. By default, this will
-accept instances of Python :class:`number.Number`. This includes in particular
-:class:`int`\s and :class:`float`\s, along with `decimal.Decimal` objects,
-:class:`complex` numbers etc. See the numbers_ module documentation for more
-details. For ``integer`` and ``object``, however, rather than checking for
-``number.Integral`` and ``collections.Mapping``, ``jsonschema`` simply checks
-for ``int`` and ``dict``, since the former can introduce significant slowdown.
+validating the JSON Schema's :validator:`type` property. Validators allow this
+by taking a ``types`` argument on construction that specifies additional types,
+or which can be used to specify a different set of Python types to map to a
+given JSON type.
+
+:mod:`jsonschema` tries to strike a balance between performance in the common
+case and generality. For instance, JSON Schema defines a ``number`` type, which
+can be validated with a schema such as ``{"type" : "number"}``. By default,
+this will accept instances of Python :class:`number.Number`. This includes in
+particular :class:`int`\s and :class:`float`\s, along with `decimal.Decimal`
+objects, :class:`complex` numbers etc. For ``integer`` and ``object``, however,
+rather than checking for :class:`number.Integral` and
+:class:`collections.Mapping`, :mod:`jsonschema` simply checks for :class:`int`
+and :class:`dict`, since the former can introduce significant slowdown in these
+common cases.
If you *do* want the generality, or just want to add a few specific additional
types as being acceptible for a validator, :class:`IValidator`\s have a
@@ -197,8 +202,6 @@ need to specify all types to match if you override one of the existing JSON
types, so you may want to access the set of default types when specifying your
additional type.
-.. _numbers: http://docs.python.org/3.3/library/numbers.html
-
.. _versioned-validators:
Versioned Validators
@@ -217,10 +220,11 @@ implements.
Validating Formats
------------------
-JSON Schema defines the ``format`` property which can be used to check if
-primitive types (``str``\s, ``number``\s, ``bool``\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 :class:`IValidator`.
+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
+:class:`IValidator`.
.. doctest::
@@ -270,7 +274,7 @@ Checker Notes
========== ====================
hostname
ipv4
-ipv6 OS must have ``socket.inet_pton`` function
+ipv6 OS must have :func:`socket.inet_pton` function
email
uri requires rfc3987_
date-time requires isodate_