summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Berman <Julian@GrayVines.com>2013-05-12 23:52:08 -0400
committerJulian Berman <Julian@GrayVines.com>2013-05-12 23:53:04 -0400
commitfc75480f092dfcac2cf28e586c2b0478062ea12f (patch)
tree265fdd2ff10dea7779edd6b0aeba5a8b01d6d75b
parentd8fd3f8bd2f60daec80040972a9d55a1eae1bc42 (diff)
parentcaca66735074820133ec754cb834aa38628a9b35 (diff)
downloadjsonschema-fc75480f092dfcac2cf28e586c2b0478062ea12f.tar.gz
Merge branch 'split_into_package'
Closes: #101
-rw-r--r--jsonschema/__init__.py25
-rw-r--r--jsonschema/_format.py215
-rw-r--r--jsonschema/_utils.py207
-rw-r--r--jsonschema/compat.py30
-rw-r--r--jsonschema/schemas/draft3.json201
-rw-r--r--jsonschema/schemas/draft4.json221
-rw-r--r--jsonschema/validators.py (renamed from jsonschema.py)729
-rw-r--r--setup.py3
-rw-r--r--test_jsonschema.py (renamed from tests.py)11
-rw-r--r--tox.ini12
10 files changed, 943 insertions, 711 deletions
diff --git a/jsonschema/__init__.py b/jsonschema/__init__.py
new file mode 100644
index 0000000..adf9e2d
--- /dev/null
+++ b/jsonschema/__init__.py
@@ -0,0 +1,25 @@
+"""
+An implementation of JSON Schema for Python
+
+The main functionality is provided by the validator classes for each of the
+supported JSON Schema versions.
+
+Most commonly, :func:`validate` is the quickest way to simply validate a given
+instance under a schema, and will create a validator for you.
+
+"""
+
+from jsonschema._format import (
+ FormatChecker, FormatError, draft3_format_checker, draft4_format_checker,
+)
+from jsonschema.validators import (
+ RefResolutionError, SchemaError, ValidationError, UnknownType,
+ ErrorTree, Draft3Validator, Draft4Validator, RefResolver, ValidatorMixin,
+ validate, validates,
+)
+
+
+__version__ = "1.4.0-dev"
+
+
+# flake8: noqa
diff --git a/jsonschema/_format.py b/jsonschema/_format.py
new file mode 100644
index 0000000..238e7117
--- /dev/null
+++ b/jsonschema/_format.py
@@ -0,0 +1,215 @@
+import datetime
+import re
+import socket
+
+from jsonschema.compat import PY3
+
+
+class FormatError(Exception):
+ def __init__(self, message, cause=None):
+ super(FormatError, self).__init__(message, cause)
+ self.message = message
+ self.cause = self.__cause__ = cause
+
+ def __str__(self):
+ return self.message.encode("utf-8")
+
+ def __unicode__(self):
+ return self.message
+
+ if PY3:
+ __str__ = __unicode__
+
+
+class FormatChecker(object):
+ """
+ A ``format`` property checker.
+
+ JSON Schema does not mandate that the ``format`` property actually do any
+ validation. If validation is desired however, instances of this class can
+ be hooked into validators to enable format validation.
+
+ :class:`FormatChecker` objects always return ``True`` when asked about
+ formats that they do not know how to validate.
+
+ To check a custom format using a function that takes an instance and
+ returns a ``bool``, use the :meth:`FormatChecker.checks` or
+ :meth:`FormatChecker.cls_checks` decorators.
+
+ :argument iterable formats: the known formats to validate. This argument
+ can be used to limit which formats will be used
+ during validation.
+
+ """
+
+ checkers = {}
+
+ def __init__(self, formats=None):
+ if formats is None:
+ self.checkers = self.checkers.copy()
+ else:
+ self.checkers = dict((k, self.checkers[k]) for k in formats)
+
+ def checks(self, format, raises=()):
+ """
+ Register a decorated function as validating a new format.
+
+ :argument str format: the format that the decorated function will check
+ :argument Exception raises: the exception(s) raised by the decorated
+ function when an invalid instance is found. The exception object
+ will be accessible as the :attr:`ValidationError.cause` attribute
+ of the resulting validation error.
+
+ """
+
+ def _checks(func):
+ self.checkers[format] = (func, raises)
+ return func
+ return _checks
+
+ cls_checks = classmethod(checks)
+
+ def check(self, instance, format):
+ """
+ Check whether the instance conforms to the given format.
+
+ :argument instance: the instance to check
+ :type: any primitive type (str, number, bool)
+ :argument str format: the format that instance should conform to
+ :raises: :exc:`FormatError` if instance does not conform to format
+
+ """
+
+ if format in self.checkers:
+ func, raises = self.checkers[format]
+ result, cause = None, None
+ try:
+ result = func(instance)
+ except raises as e:
+ cause = e
+ if not result:
+ raise FormatError(
+ "%r is not a %r" % (instance, format), cause=cause,
+ )
+
+ def conforms(self, instance, format):
+ """
+ Check whether the instance conforms to the given format.
+
+ :argument instance: the instance to check
+ :type: any primitive type (str, number, bool)
+ :argument str format: the format that instance should conform to
+ :rtype: bool
+
+ """
+
+ try:
+ self.check(instance, format)
+ except FormatError:
+ return False
+ else:
+ return True
+
+
+_draft_checkers = {"draft3": [], "draft4": []}
+
+
+def _checks_drafts(both=None, draft3=None, draft4=None, raises=()):
+ draft3 = draft3 or both
+ draft4 = draft4 or both
+
+ def wrap(func):
+ if draft3:
+ _draft_checkers["draft3"].append(draft3)
+ func = FormatChecker.cls_checks(draft3, raises)(func)
+ if draft4:
+ _draft_checkers["draft4"].append(draft4)
+ func = FormatChecker.cls_checks(draft4, raises)(func)
+ return func
+ return wrap
+
+
+@_checks_drafts("email")
+def is_email(instance):
+ return "@" in instance
+
+
+_checks_drafts(draft3="ip-address", draft4="ipv4", raises=socket.error)(
+ socket.inet_aton
+)
+
+
+if hasattr(socket, "inet_pton"):
+ @_checks_drafts("ipv6", raises=socket.error)
+ def is_ipv6(instance):
+ return socket.inet_pton(socket.AF_INET6, instance)
+
+
+@_checks_drafts(draft3="host-name", draft4="hostname")
+def is_host_name(instance):
+ pattern = "^[A-Za-z0-9][A-Za-z0-9\.\-]{1,255}$"
+ if not re.match(pattern, instance):
+ return False
+ components = instance.split(".")
+ for component in components:
+ if len(component) > 63:
+ return False
+ return True
+
+
+try:
+ import rfc3987
+except ImportError:
+ pass
+else:
+ @_checks_drafts("uri", raises=ValueError)
+ def is_uri(instance):
+ return rfc3987.parse(instance, rule="URI_reference")
+
+
+try:
+ import isodate
+except ImportError:
+ pass
+else:
+ _err = (ValueError, isodate.ISO8601Error)
+ _checks_drafts("date-time", raises=_err)(isodate.parse_datetime)
+
+
+_checks_drafts("regex", raises=re.error)(re.compile)
+
+
+@_checks_drafts(draft3="date", raises=ValueError)
+def is_date(instance):
+ return datetime.datetime.strptime(instance, "%Y-%m-%d")
+
+
+@_checks_drafts(draft3="time", raises=ValueError)
+def is_time(instance):
+ return datetime.datetime.strptime(instance, "%H:%M:%S")
+
+
+try:
+ import webcolors
+except ImportError:
+ pass
+else:
+ def is_css_color_code(instance):
+ return webcolors.normalize_hex(instance)
+
+
+ @_checks_drafts(draft3="color", raises=(ValueError, TypeError))
+ def is_css21_color(instance):
+ if instance.lower() in webcolors.css21_names_to_hex:
+ return True
+ return is_css_color_code(instance)
+
+
+ def is_css3_color(instance):
+ if instance.lower() in webcolors.css3_names_to_hex:
+ return True
+ return is_css_color_code(instance)
+
+
+draft3_format_checker = FormatChecker(_draft_checkers["draft3"])
+draft4_format_checker = FormatChecker(_draft_checkers["draft4"])
diff --git a/jsonschema/_utils.py b/jsonschema/_utils.py
new file mode 100644
index 0000000..10e7bf8
--- /dev/null
+++ b/jsonschema/_utils.py
@@ -0,0 +1,207 @@
+import itertools
+import json
+import re
+import os
+
+from jsonschema.compat import str_types, urlparse, MutableMapping
+
+
+class URIDict(MutableMapping):
+ """
+ Dictionary which uses normalized URIs as keys.
+
+ """
+
+ def normalize(self, uri):
+ return urlparse.urlsplit(uri).geturl()
+
+ def __init__(self, *args, **kwargs):
+ self.store = dict()
+ self.store.update(*args, **kwargs)
+
+ def __getitem__(self, uri):
+ return self.store[self.normalize(uri)]
+
+ def __setitem__(self, uri, value):
+ self.store[self.normalize(uri)] = value
+
+ def __delitem__(self, uri):
+ del self.store[self.normalize(uri)]
+
+ def __iter__(self):
+ return iter(self.store)
+
+ def __len__(self):
+ return len(self.store)
+
+ def __repr__(self):
+ return repr(self.store)
+
+
+def load_schema(name):
+ """
+ Load a schema from ./schemas/``name``.json and return it.
+
+ """
+ schemadir = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ 'schemas'
+ )
+ schemapath = os.path.join(schemadir, '%s.json' % (name,))
+ with open(schemapath) as f:
+ return json.load(f)
+
+
+def indent(string, times=1):
+ """
+ A dumb version of :func:`textwrap.indent` from Python 3.3.
+
+ """
+
+ return "\n".join(" " * (4 * times) + line for line in string.splitlines())
+
+
+def format_as_index(indices):
+ """
+ Construct a single string containing indexing operations for the indices.
+
+ For example, [1, 2, "foo"] -> [1][2]["foo"]
+
+ :type indices: sequence
+
+ """
+
+ if not indices:
+ return ""
+ return "[%s]" % "][".join(repr(index) for index in indices)
+
+
+def find_additional_properties(instance, schema):
+ """
+ Return the set of additional properties for the given ``instance``.
+
+ Weeds out properties that should have been validated by ``properties`` and
+ / or ``patternProperties``.
+
+ Assumes ``instance`` is dict-like already.
+
+ """
+
+ properties = schema.get("properties", {})
+ patterns = "|".join(schema.get("patternProperties", {}))
+ for property in instance:
+ if property not in properties:
+ if patterns and re.search(patterns, property):
+ continue
+ yield property
+
+
+def extras_msg(extras):
+ """
+ Create an error message for extra items or properties.
+
+ """
+
+ if len(extras) == 1:
+ verb = "was"
+ else:
+ verb = "were"
+ return ", ".join(repr(extra) for extra in extras), verb
+
+
+def types_msg(instance, types):
+ """
+ Create an error message for a failure to match the given types.
+
+ If the ``instance`` is an object and contains a ``name`` property, it will
+ be considered to be a description of that object and used as its type.
+
+ Otherwise the message is simply the reprs of the given ``types``.
+
+ """
+
+ reprs = []
+ for type in types:
+ try:
+ reprs.append(repr(type["name"]))
+ except Exception:
+ reprs.append(repr(type))
+ return "%r is not of type %s" % (instance, ", ".join(reprs))
+
+
+def flatten(suitable_for_isinstance):
+ """
+ isinstance() can accept a bunch of really annoying different types:
+ * a single type
+ * a tuple of types
+ * an arbitrary nested tree of tuples
+
+ Return a flattened tuple of the given argument.
+
+ """
+
+ types = set()
+
+ if not isinstance(suitable_for_isinstance, tuple):
+ suitable_for_isinstance = (suitable_for_isinstance,)
+ for thing in suitable_for_isinstance:
+ if isinstance(thing, tuple):
+ types.update(flatten(thing))
+ else:
+ types.add(thing)
+ return tuple(types)
+
+
+def ensure_list(thing):
+ """
+ Wrap ``thing`` in a list if it's a single str.
+
+ Otherwise, return it unchanged.
+
+ """
+
+ if isinstance(thing, str_types):
+ return [thing]
+ return thing
+
+
+def unbool(element, true=object(), false=object()):
+ """
+ A hack to make True and 1 and False and 0 unique for ``uniq``.
+
+ """
+
+ if element is True:
+ return true
+ elif element is False:
+ return false
+ return element
+
+
+def uniq(container):
+ """
+ Check if all of a container's elements are unique.
+
+ Successively tries first to rely that the elements are hashable, then
+ falls back on them being sortable, and finally falls back on brute
+ force.
+
+ """
+
+ try:
+ return len(set(unbool(i) for i in container)) == len(container)
+ except TypeError:
+ try:
+ sort = sorted(unbool(i) for i in container)
+ sliced = itertools.islice(sort, 1, None)
+ for i, j in zip(sort, sliced):
+ if i == j:
+ return False
+ except (NotImplementedError, TypeError):
+ seen = []
+ for e in container:
+ e = unbool(e)
+ if e in seen:
+ return False
+ seen.append(e)
+ return True
diff --git a/jsonschema/compat.py b/jsonschema/compat.py
new file mode 100644
index 0000000..44c6ede
--- /dev/null
+++ b/jsonschema/compat.py
@@ -0,0 +1,30 @@
+from __future__ import unicode_literals
+import sys
+import operator
+
+try:
+ from collections import MutableMapping, Sequence # noqa
+except ImportError:
+ from collections.abc import MutableMapping, Sequence # noqa
+
+PY3 = sys.version_info[0] >= 3
+
+if PY3:
+ zip = zip
+ from urllib import parse as urlparse
+ from urllib.parse import unquote
+ 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 urllib import unquote # noqa
+ from urllib2 import urlopen # noqa
+ str_types = basestring
+ int_types = int, long
+ iteritems = operator.methodcaller("iteritems")
+
+
+# flake8: noqa
diff --git a/jsonschema/schemas/draft3.json b/jsonschema/schemas/draft3.json
new file mode 100644
index 0000000..5bcefe3
--- /dev/null
+++ b/jsonschema/schemas/draft3.json
@@ -0,0 +1,201 @@
+{
+ "$schema": "http://json-schema.org/draft-03/schema#",
+ "dependencies": {
+ "exclusiveMaximum": "maximum",
+ "exclusiveMinimum": "minimum"
+ },
+ "id": "http://json-schema.org/draft-03/schema#",
+ "properties": {
+ "$ref": {
+ "format": "uri",
+ "type": "string"
+ },
+ "$schema": {
+ "format": "uri",
+ "type": "string"
+ },
+ "additionalItems": {
+ "default": {},
+ "type": [
+ {
+ "$ref": "#"
+ },
+ "boolean"
+ ]
+ },
+ "additionalProperties": {
+ "default": {},
+ "type": [
+ {
+ "$ref": "#"
+ },
+ "boolean"
+ ]
+ },
+ "default": {
+ "type": "any"
+ },
+ "dependencies": {
+ "additionalProperties": {
+ "items": {
+ "type": "string"
+ },
+ "type": [
+ "string",
+ "array",
+ {
+ "$ref": "#"
+ }
+ ]
+ },
+ "default": {},
+ "type": [
+ "string",
+ "array",
+ "object"
+ ]
+ },
+ "description": {
+ "type": "string"
+ },
+ "disallow": {
+ "items": {
+ "type": [
+ "string",
+ {
+ "$ref": "#"
+ }
+ ]
+ },
+ "type": [
+ "string",
+ "array"
+ ],
+ "uniqueItems": true
+ },
+ "divisibleBy": {
+ "default": 1,
+ "exclusiveMinimum": true,
+ "minimum": 0,
+ "type": "number"
+ },
+ "enum": {
+ "minItems": 1,
+ "type": "array",
+ "uniqueItems": true
+ },
+ "exclusiveMaximum": {
+ "default": false,
+ "type": "boolean"
+ },
+ "exclusiveMinimum": {
+ "default": false,
+ "type": "boolean"
+ },
+ "extends": {
+ "default": {},
+ "items": {
+ "$ref": "#"
+ },
+ "type": [
+ {
+ "$ref": "#"
+ },
+ "array"
+ ]
+ },
+ "format": {
+ "type": "string"
+ },
+ "id": {
+ "format": "uri",
+ "type": "string"
+ },
+ "items": {
+ "default": {},
+ "items": {
+ "$ref": "#"
+ },
+ "type": [
+ {
+ "$ref": "#"
+ },
+ "array"
+ ]
+ },
+ "maxDecimal": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "maxItems": {
+ "minimum": 0,
+ "type": "integer"
+ },
+ "maxLength": {
+ "type": "integer"
+ },
+ "maximum": {
+ "type": "number"
+ },
+ "minItems": {
+ "default": 0,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "minLength": {
+ "default": 0,
+ "minimum": 0,
+ "type": "integer"
+ },
+ "minimum": {
+ "type": "number"
+ },
+ "pattern": {
+ "format": "regex",
+ "type": "string"
+ },
+ "patternProperties": {
+ "additionalProperties": {
+ "$ref": "#"
+ },
+ "default": {},
+ "type": "object"
+ },
+ "properties": {
+ "additionalProperties": {
+ "$ref": "#",
+ "type": "object"
+ },
+ "default": {},
+ "type": "object"
+ },
+ "required": {
+ "default": false,
+ "type": "boolean"
+ },
+ "title": {
+ "type": "string"
+ },
+ "type": {
+ "default": "any",
+ "items": {
+ "type": [
+ "string",
+ {
+ "$ref": "#"
+ }
+ ]
+ },
+ "type": [
+ "string",
+ "array"
+ ],
+ "uniqueItems": true
+ },
+ "uniqueItems": {
+ "default": false,
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+}
diff --git a/jsonschema/schemas/draft4.json b/jsonschema/schemas/draft4.json
new file mode 100644
index 0000000..fead5ce
--- /dev/null
+++ b/jsonschema/schemas/draft4.json
@@ -0,0 +1,221 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "default": {},
+ "definitions": {
+ "positiveInteger": {
+ "minimum": 0,
+ "type": "integer"
+ },
+ "positiveIntegerDefault0": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/positiveInteger"
+ },
+ {
+ "default": 0
+ }
+ ]
+ },
+ "schemaArray": {
+ "items": {
+ "$ref": "#"
+ },
+ "minItems": 1,
+ "type": "array"
+ },
+ "simpleTypes": {
+ "enum": [
+ "array",
+ "boolean",
+ "integer",
+ "null",
+ "number",
+ "object",
+ "string"
+ ]
+ },
+ "stringArray": {
+ "items": {
+ "type": "string"
+ },
+ "minItems": 1,
+ "type": "array",
+ "uniqueItems": true
+ }
+ },
+ "dependencies": {
+ "exclusiveMaximum": [
+ "maximum"
+ ],
+ "exclusiveMinimum": [
+ "minimum"
+ ]
+ },
+ "description": "Core schema meta-schema",
+ "id": "http://json-schema.org/draft-04/schema#",
+ "properties": {
+ "$schema": {
+ "format": "uri",
+ "type": "string"
+ },
+ "additionalItems": {
+ "anyOf": [
+ {
+ "type": "boolean"
+ },
+ {
+ "$ref": "#"
+ }
+ ],
+ "default": {}
+ },
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "type": "boolean"
+ },
+ {
+ "$ref": "#"
+ }
+ ],
+ "default": {}
+ },
+ "allOf": {
+ "$ref": "#/definitions/schemaArray"
+ },
+ "anyOf": {
+ "$ref": "#/definitions/schemaArray"
+ },
+ "default": {},
+ "definitions": {
+ "additionalProperties": {
+ "$ref": "#"
+ },
+ "default": {},
+ "type": "object"
+ },
+ "dependencies": {
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/stringArray"
+ }
+ ]
+ },
+ "type": "object"
+ },
+ "description": {
+ "type": "string"
+ },
+ "enum": {
+ "minItems": 1,
+ "type": "array",
+ "uniqueItems": true
+ },
+ "exclusiveMaximum": {
+ "default": false,
+ "type": "boolean"
+ },
+ "exclusiveMinimum": {
+ "default": false,
+ "type": "boolean"
+ },
+ "id": {
+ "format": "uri",
+ "type": "string"
+ },
+ "items": {
+ "anyOf": [
+ {
+ "$ref": "#"
+ },
+ {
+ "$ref": "#/definitions/schemaArray"
+ }
+ ],
+ "default": {}
+ },
+ "maxItems": {
+ "$ref": "#/definitions/positiveInteger"
+ },
+ "maxLength": {
+ "$ref": "#/definitions/positiveInteger"
+ },
+ "maxProperties": {
+ "$ref": "#/definitions/positiveInteger"
+ },
+ "maximum": {
+ "type": "number"
+ },
+ "minItems": {
+ "$ref": "#/definitions/positiveIntegerDefault0"
+ },
+ "minLength": {
+ "$ref": "#/definitions/positiveIntegerDefault0"
+ },
+ "minProperties": {
+ "$ref": "#/definitions/positiveIntegerDefault0"
+ },
+ "minimum": {
+ "type": "number"
+ },
+ "multipleOf": {
+ "exclusiveMinimum": true,
+ "minimum": 0,
+ "type": "number"
+ },
+ "not": {
+ "$ref": "#"
+ },
+ "oneOf": {
+ "$ref": "#/definitions/schemaArray"
+ },
+ "pattern": {
+ "format": "regex",
+ "type": "string"
+ },
+ "patternProperties": {
+ "additionalProperties": {
+ "$ref": "#"
+ },
+ "default": {},
+ "type": "object"
+ },
+ "properties": {
+ "additionalProperties": {
+ "$ref": "#"
+ },
+ "default": {},
+ "type": "object"
+ },
+ "required": {
+ "$ref": "#/definitions/stringArray"
+ },
+ "title": {
+ "type": "string"
+ },
+ "type": {
+ "anyOf": [
+ {
+ "$ref": "#/definitions/simpleTypes"
+ },
+ {
+ "items": {
+ "$ref": "#/definitions/simpleTypes"
+ },
+ "minItems": 1,
+ "type": "array",
+ "uniqueItems": true
+ }
+ ]
+ },
+ "uniqueItems": {
+ "default": false,
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+}
diff --git a/jsonschema.py b/jsonschema/validators.py
index 2f4dab5..9741125 100644
--- a/jsonschema.py
+++ b/jsonschema/validators.py
@@ -1,56 +1,23 @@
-"""
-An implementation of JSON Schema for Python
-
-The main functionality is provided by the validator classes for each of the
-supported JSON Schema versions.
-
-Most commonly, :func:`validate` is the quickest way to simply validate a given
-instance under a schema, and will create a validator for you.
-
-"""
-
from __future__ import division, unicode_literals
import collections
import contextlib
-import datetime
-import itertools
import json
import numbers
-import operator
import pprint
import re
-import socket
-import sys
import textwrap
try:
- from collections import MutableMapping, Sequence
-except ImportError:
- from collections.abc import MutableMapping, Sequence
-
-try:
import requests
except ImportError:
requests = None
-__version__ = "1.4.0-dev"
-
-PY3 = sys.version_info[0] >= 3
-
-if PY3:
- from urllib import parse as urlparse
- from urllib.parse import unquote
- from urllib.request import urlopen
- basestring = unicode = str
- long = int
- iteritems = operator.methodcaller("items")
-else:
- from itertools import izip as zip
- from urllib import unquote
- from urllib2 import urlopen
- import urlparse
- iteritems = operator.methodcaller("iteritems")
+from jsonschema import _utils
+from jsonschema.compat import (
+ PY3, Sequence, urlparse, unquote, urlopen, str_types, int_types, iteritems,
+)
+from jsonschema._format import FormatError
FLOAT_TOLERANCE = 10 ** -15
@@ -114,8 +81,8 @@ class _Error(Exception):
):
return self.message
- path = _format_as_index(self.path)
- schema_path = _format_as_index(list(self.schema_path)[:-1])
+ path = _utils.format_as_index(self.path)
+ schema_path = _utils.format_as_index(list(self.schema_path)[:-1])
pschema = pprint.pformat(self.schema, width=72)
pinstance = pprint.pformat(self.instance, width=72)
@@ -130,70 +97,22 @@ class _Error(Exception):
) % (
self.validator,
schema_path,
- _indent(pschema),
+ _utils.indent(pschema),
path,
- _indent(pinstance),
+ _utils.indent(pinstance),
)
if PY3:
__str__ = __unicode__
-class FormatError(Exception):
- def __init__(self, message, cause=None):
- super(FormatError, self).__init__(message, cause)
- self.message = message
- self.cause = self.__cause__ = cause
-
- def __str__(self):
- return self.message.encode("utf-8")
-
- def __unicode__(self):
- return self.message
-
- if PY3:
- __str__ = __unicode__
-
-
class SchemaError(_Error): pass
class ValidationError(_Error): pass
class RefResolutionError(Exception): pass
class UnknownType(Exception): pass
-class _URIDict(MutableMapping):
- """
- Dictionary which uses normalized URIs as keys.
-
- """
-
- def normalize(self, uri):
- return urlparse.urlsplit(uri).geturl()
-
- def __init__(self, *args, **kwargs):
- self.store = dict()
- self.store.update(*args, **kwargs)
-
- def __getitem__(self, uri):
- return self.store[self.normalize(uri)]
-
- def __setitem__(self, uri, value):
- self.store[self.normalize(uri)] = value
-
- def __delitem__(self, uri):
- del self.store[self.normalize(uri)]
-
- def __iter__(self):
- return iter(self.store)
-
- def __len__(self):
- return len(self.store)
-
- def __repr__(self):
- return repr(self.store)
-
-
-meta_schemas = _URIDict()
+meta_schemas = _utils.URIDict()
def validates(version):
@@ -229,9 +148,9 @@ class ValidatorMixin(object):
"""
DEFAULT_TYPES = {
- "array" : list, "boolean" : bool, "integer" : (int, long),
+ "array" : list, "boolean" : bool, "integer" : int_types,
"null" : type(None), "number" : numbers.Number, "object" : dict,
- "string" : basestring,
+ "string" : str_types,
}
def __init__(self, schema, types=(), resolver=None, format_checker=None):
@@ -252,7 +171,7 @@ class ValidatorMixin(object):
# bool inherits from int, so ensure bools aren't reported as integers
if isinstance(instance, bool):
- pytypes = _flatten(pytypes)
+ pytypes = _utils.flatten(pytypes)
num = any(issubclass(pytype, numbers.Number) for pytype in pytypes)
if num and bool not in pytypes:
return False
@@ -333,7 +252,7 @@ class _Draft34CommonMixin(object):
if not self.is_type(instance, "object"):
return
- extras = set(_find_additional_properties(instance, schema))
+ extras = set(_utils.find_additional_properties(instance, schema))
if self.is_type(aP, "object"):
for extra in extras:
@@ -341,7 +260,7 @@ class _Draft34CommonMixin(object):
yield error
elif not aP and extras:
error = "Additional properties are not allowed (%s %s unexpected)"
- yield ValidationError(error % _extras_msg(extras))
+ yield ValidationError(error % _utils.extras_msg(extras))
def validate_items(self, items, instance, schema):
if not self.is_type(instance, "array"):
@@ -373,7 +292,8 @@ class _Draft34CommonMixin(object):
elif not aI and len(instance) > len(schema.get("items", [])):
error = "Additional items are not allowed (%s %s unexpected)"
yield ValidationError(
- error % _extras_msg(instance[len(schema.get("items", [])):])
+ error %
+ _utils.extras_msg(instance[len(schema.get("items", [])):])
)
def validate_minimum(self, minimum, instance, schema):
@@ -434,7 +354,11 @@ class _Draft34CommonMixin(object):
yield ValidationError("%r is too long" % (instance,))
def validate_uniqueItems(self, uI, instance, schema):
- if uI and self.is_type(instance, "array") and not _uniq(instance):
+ if (
+ uI and
+ self.is_type(instance, "array") and
+ not _utils.uniq(instance)
+ ):
yield ValidationError("%r has non-unique elements" % instance)
def validate_pattern(self, patrn, instance, schema):
@@ -473,7 +397,7 @@ class _Draft34CommonMixin(object):
):
yield error
else:
- dependencies = _list(dependency)
+ dependencies = _utils.ensure_list(dependency)
for dependency in dependencies:
if dependency not in instance:
yield ValidationError(
@@ -498,7 +422,7 @@ class Draft3Validator(ValidatorMixin, _Draft34CommonMixin, object):
"""
def validate_type(self, types, instance, schema):
- types = _list(types)
+ types = _utils.ensure_list(types)
all_errors = []
for index, type in enumerate(types):
@@ -514,7 +438,7 @@ class Draft3Validator(ValidatorMixin, _Draft34CommonMixin, object):
return
else:
yield ValidationError(
- _types_msg(instance, types), context=all_errors,
+ _utils.types_msg(instance, types), context=all_errors,
)
def validate_properties(self, properties, instance, schema):
@@ -543,7 +467,7 @@ class Draft3Validator(ValidatorMixin, _Draft34CommonMixin, object):
yield error
def validate_disallow(self, disallow, instance, schema):
- for disallowed in _list(disallow):
+ for disallowed in _utils.ensure_list(disallow):
if self.is_valid(instance, {"type" : [disallowed]}):
yield ValidationError(
"%r is disallowed for %r" % (disallowed, instance)
@@ -560,88 +484,7 @@ class Draft3Validator(ValidatorMixin, _Draft34CommonMixin, object):
validate_divisibleBy = _Draft34CommonMixin._validate_multipleOf
- META_SCHEMA = {
- "$schema" : "http://json-schema.org/draft-03/schema#",
- "id" : "http://json-schema.org/draft-03/schema#",
- "type" : "object",
-
- "properties" : {
- "type" : {
- "type" : ["string", "array"],
- "items" : {"type" : ["string", {"$ref" : "#"}]},
- "uniqueItems" : True,
- "default" : "any"
- },
- "properties" : {
- "type" : "object",
- "additionalProperties" : {"$ref" : "#", "type": "object"},
- "default" : {}
- },
- "patternProperties" : {
- "type" : "object",
- "additionalProperties" : {"$ref" : "#"},
- "default" : {}
- },
- "additionalProperties" : {
- "type" : [{"$ref" : "#"}, "boolean"], "default" : {}
- },
- "items" : {
- "type" : [{"$ref" : "#"}, "array"],
- "items" : {"$ref" : "#"},
- "default" : {}
- },
- "additionalItems" : {
- "type" : [{"$ref" : "#"}, "boolean"], "default" : {}
- },
- "required" : {"type" : "boolean", "default" : False},
- "dependencies" : {
- "type" : ["string", "array", "object"],
- "additionalProperties" : {
- "type" : ["string", "array", {"$ref" : "#"}],
- "items" : {"type" : "string"}
- },
- "default" : {}
- },
- "minimum" : {"type" : "number"},
- "maximum" : {"type" : "number"},
- "exclusiveMinimum" : {"type" : "boolean", "default" : False},
- "exclusiveMaximum" : {"type" : "boolean", "default" : False},
- "minItems" : {"type" : "integer", "minimum" : 0, "default" : 0},
- "maxItems" : {"type" : "integer", "minimum" : 0},
- "uniqueItems" : {"type" : "boolean", "default" : False},
- "pattern" : {"type" : "string", "format" : "regex"},
- "minLength" : {"type" : "integer", "minimum" : 0, "default" : 0},
- "maxLength" : {"type" : "integer"},
- "enum" : {"type" : "array", "minItems" : 1, "uniqueItems" : True},
- "default" : {"type" : "any"},
- "title" : {"type" : "string"},
- "description" : {"type" : "string"},
- "format" : {"type" : "string"},
- "maxDecimal" : {"type" : "number", "minimum" : 0},
- "divisibleBy" : {
- "type" : "number",
- "minimum" : 0,
- "exclusiveMinimum" : True,
- "default" : 1
- },
- "disallow" : {
- "type" : ["string", "array"],
- "items" : {"type" : ["string", {"$ref" : "#"}]},
- "uniqueItems" : True
- },
- "extends" : {
- "type" : [{"$ref" : "#"}, "array"],
- "items" : {"$ref" : "#"},
- "default" : {}
- },
- "id" : {"type" : "string", "format" : "uri"},
- "$ref" : {"type" : "string", "format" : "uri"},
- "$schema" : {"type" : "string", "format" : "uri"},
- },
- "dependencies" : {
- "exclusiveMinimum" : "minimum", "exclusiveMaximum" : "maximum"
- },
- }
+ META_SCHEMA = _utils.load_schema('draft3')
@validates("draft4")
@@ -652,10 +495,10 @@ class Draft4Validator(ValidatorMixin, _Draft34CommonMixin, object):
"""
def validate_type(self, types, instance, schema):
- types = _list(types)
+ types = _utils.ensure_list(types)
if not any(self.is_type(instance, type) for type in types):
- yield ValidationError(_types_msg(instance, types))
+ yield ValidationError(_utils.types_msg(instance, types))
def validate_properties(self, properties, instance, schema):
if not self.is_type(instance, "object"):
@@ -737,362 +580,7 @@ class Draft4Validator(ValidatorMixin, _Draft34CommonMixin, object):
validate_multipleOf = _Draft34CommonMixin._validate_multipleOf
- META_SCHEMA = {
- "id": "http://json-schema.org/draft-04/schema#",
- "$schema": "http://json-schema.org/draft-04/schema#",
- "description": "Core schema meta-schema",
- "definitions": {
- "schemaArray": {
- "type": "array",
- "minItems": 1,
- "items": {"$ref": "#"}
- },
- "positiveInteger": {
- "type": "integer",
- "minimum": 0
- },
- "positiveIntegerDefault0": {
- "allOf": [
- {"$ref": "#/definitions/positiveInteger"}, {"default": 0}
- ]
- },
- "simpleTypes": {
- "enum": [
- "array",
- "boolean",
- "integer",
- "null",
- "number",
- "object",
- "string",
- ]
- },
- "stringArray": {
- "type": "array",
- "items": {"type": "string"},
- "minItems": 1,
- "uniqueItems": True
- }
- },
- "type": "object",
- "properties": {
- "id": {
- "type": "string",
- "format": "uri"
- },
- "$schema": {
- "type": "string",
- "format": "uri"
- },
- "title": {
- "type": "string"
- },
- "description": {
- "type": "string"
- },
- "default": {},
- "multipleOf": {
- "type": "number",
- "minimum": 0,
- "exclusiveMinimum": True
- },
- "maximum": {
- "type": "number"
- },
- "exclusiveMaximum": {
- "type": "boolean",
- "default": False
- },
- "minimum": {
- "type": "number"
- },
- "exclusiveMinimum": {
- "type": "boolean",
- "default": False
- },
- "maxLength": {"$ref": "#/definitions/positiveInteger"},
- "minLength": {"$ref": "#/definitions/positiveIntegerDefault0"},
- "pattern": {
- "type": "string",
- "format": "regex"
- },
- "additionalItems": {
- "anyOf": [
- {"type": "boolean"},
- {"$ref": "#"}
- ],
- "default": {}
- },
- "items": {
- "anyOf": [
- {"$ref": "#"},
- {"$ref": "#/definitions/schemaArray"}
- ],
- "default": {}
- },
- "maxItems": {"$ref": "#/definitions/positiveInteger"},
- "minItems": {"$ref": "#/definitions/positiveIntegerDefault0"},
- "uniqueItems": {
- "type": "boolean",
- "default": False
- },
- "maxProperties": {"$ref": "#/definitions/positiveInteger"},
- "minProperties": {"$ref": "#/definitions/positiveIntegerDefault0"},
- "required": {"$ref": "#/definitions/stringArray"},
- "additionalProperties": {
- "anyOf": [
- {"type": "boolean"},
- {"$ref": "#"}
- ],
- "default": {}
- },
- "definitions": {
- "type": "object",
- "additionalProperties": {"$ref": "#"},
- "default": {}
- },
- "properties": {
- "type": "object",
- "additionalProperties": {"$ref": "#"},
- "default": {}
- },
- "patternProperties": {
- "type": "object",
- "additionalProperties": {"$ref": "#"},
- "default": {}
- },
- "dependencies": {
- "type": "object",
- "additionalProperties": {
- "anyOf": [
- {"$ref": "#"},
- {"$ref": "#/definitions/stringArray"}
- ]
- }
- },
- "enum": {
- "type": "array",
- "minItems": 1,
- "uniqueItems": True
- },
- "type": {
- "anyOf": [
- {"$ref": "#/definitions/simpleTypes"},
- {
- "type": "array",
- "items": {"$ref": "#/definitions/simpleTypes"},
- "minItems": 1,
- "uniqueItems": True
- }
- ]
- },
- "allOf": {"$ref": "#/definitions/schemaArray"},
- "anyOf": {"$ref": "#/definitions/schemaArray"},
- "oneOf": {"$ref": "#/definitions/schemaArray"},
- "not": {"$ref": "#"}
- },
- "dependencies": {
- "exclusiveMaximum": ["maximum"],
- "exclusiveMinimum": ["minimum"]
- },
- "default": {}
- }
-
-
-class FormatChecker(object):
- """
- A ``format`` property checker.
-
- JSON Schema does not mandate that the ``format`` property actually do any
- validation. If validation is desired however, instances of this class can
- be hooked into validators to enable format validation.
-
- :class:`FormatChecker` objects always return ``True`` when asked about
- formats that they do not know how to validate.
-
- To check a custom format using a function that takes an instance and
- returns a ``bool``, use the :meth:`FormatChecker.checks` or
- :meth:`FormatChecker.cls_checks` decorators.
-
- :argument iterable formats: the known formats to validate. This argument
- can be used to limit which formats will be used
- during validation.
-
- >>> checker = FormatChecker(formats=("date-time", "regex"))
-
- """
-
- checkers = {}
-
- def __init__(self, formats=None):
- if formats is None:
- self.checkers = self.checkers.copy()
- else:
- self.checkers = dict((k, self.checkers[k]) for k in formats)
-
- def checks(self, format, raises=()):
- """
- Register a decorated function as validating a new format.
-
- :argument str format: the format that the decorated function will check
- :argument Exception raises: the exception(s) raised by the decorated
- function when an invalid instance is found. The exception object
- will be accessible as the :attr:`ValidationError.cause` attribute
- of the resulting validation error.
-
- """
-
- def _checks(func):
- self.checkers[format] = (func, raises)
- return func
- return _checks
-
- cls_checks = classmethod(checks)
-
- def check(self, instance, format):
- """
- Check whether the instance conforms to the given format.
-
- :argument instance: the instance to check
- :type: any primitive type (str, number, bool)
- :argument str format: the format that instance should conform to
- :raises: :exc:`FormatError` if instance does not conform to format
-
- """
-
- if format in self.checkers:
- func, raises = self.checkers[format]
- result, cause = None, None
- try:
- result = func(instance)
- except raises as e:
- cause = e
- if not result:
- raise FormatError(
- "%r is not a %r" % (instance, format), cause=cause,
- )
-
- def conforms(self, instance, format):
- """
- Check whether the instance conforms to the given format.
-
- :argument instance: the instance to check
- :type: any primitive type (str, number, bool)
- :argument str format: the format that instance should conform to
- :rtype: bool
-
- """
-
- try:
- self.check(instance, format)
- except FormatError:
- return False
- else:
- return True
-
-
-_draft_checkers = {"draft3": [], "draft4": []}
-
-
-def _checks_drafts(both=None, draft3=None, draft4=None, raises=()):
- draft3 = draft3 or both
- draft4 = draft4 or both
-
- def wrap(func):
- if draft3:
- _draft_checkers["draft3"].append(draft3)
- func = FormatChecker.cls_checks(draft3, raises)(func)
- if draft4:
- _draft_checkers["draft4"].append(draft4)
- func = FormatChecker.cls_checks(draft4, raises)(func)
- return func
- return wrap
-
-
-@_checks_drafts("email")
-def is_email(instance):
- return "@" in instance
-
-
-_checks_drafts(draft3="ip-address", draft4="ipv4", raises=socket.error)(
- socket.inet_aton
-)
-
-
-if hasattr(socket, "inet_pton"):
- @_checks_drafts("ipv6", raises=socket.error)
- def is_ipv6(instance):
- return socket.inet_pton(socket.AF_INET6, instance)
-
-
-@_checks_drafts(draft3="host-name", draft4="hostname")
-def is_host_name(instance):
- pattern = "^[A-Za-z0-9][A-Za-z0-9\.\-]{1,255}$"
- if not re.match(pattern, instance):
- return False
- components = instance.split(".")
- for component in components:
- if len(component) > 63:
- return False
- return True
-
-
-try:
- import rfc3987
-except ImportError:
- pass
-else:
- @_checks_drafts("uri", raises=ValueError)
- def is_uri(instance):
- return rfc3987.parse(instance, rule="URI_reference")
-
-
-try:
- import isodate
-except ImportError:
- pass
-else:
- _err = (ValueError, isodate.ISO8601Error)
- _checks_drafts("date-time", raises=_err)(isodate.parse_datetime)
-
-
-_checks_drafts("regex", raises=re.error)(re.compile)
-
-
-@_checks_drafts(draft3="date", raises=ValueError)
-def is_date(instance):
- return datetime.datetime.strptime(instance, "%Y-%m-%d")
-
-
-@_checks_drafts(draft3="time", raises=ValueError)
-def is_time(instance):
- return datetime.datetime.strptime(instance, "%H:%M:%S")
-
-
-try:
- import webcolors
-except ImportError:
- pass
-else:
- def is_css_color_code(instance):
- return webcolors.normalize_hex(instance)
-
-
- @_checks_drafts(draft3="color", raises=(ValueError, TypeError))
- def is_css21_color(instance):
- if instance.lower() in webcolors.css21_names_to_hex:
- return True
- return is_css_color_code(instance)
-
-
- def is_css3_color(instance):
- if instance.lower() in webcolors.css3_names_to_hex:
- return True
- return is_css_color_code(instance)
-
-
-draft3_format_checker = FormatChecker(_draft_checkers["draft3"])
-draft4_format_checker = FormatChecker(_draft_checkers["draft4"])
+ META_SCHEMA = _utils.load_schema('draft4')
class RefResolver(object):
@@ -1119,7 +607,7 @@ class RefResolver(object):
self.cache_remote = cache_remote
self.handlers = dict(handlers)
- self.store = _URIDict(
+ self.store = _utils.URIDict(
(id, validator.META_SCHEMA)
for id, validator in iteritems(meta_schemas)
)
@@ -1315,161 +803,6 @@ class ErrorTree(object):
return len(self.errors) + child_errors
-def _indent(string, times=1):
- """
- A dumb version of :func:`textwrap.indent` from Python 3.3.
-
- """
-
- return "\n".join(" " * (4 * times) + line for line in string.splitlines())
-
-
-def _format_as_index(indices):
- """
- Construct a single string containing indexing operations for the indices.
-
- For example, [1, 2, "foo"] -> [1][2]["foo"]
-
- :type indices: sequence
-
- """
-
- if not indices:
- return ""
- return "[%s]" % "][".join(repr(index) for index in indices)
-
-
-def _find_additional_properties(instance, schema):
- """
- Return the set of additional properties for the given ``instance``.
-
- Weeds out properties that should have been validated by ``properties`` and
- / or ``patternProperties``.
-
- Assumes ``instance`` is dict-like already.
-
- """
-
- properties = schema.get("properties", {})
- patterns = "|".join(schema.get("patternProperties", {}))
- for property in instance:
- if property not in properties:
- if patterns and re.search(patterns, property):
- continue
- yield property
-
-
-def _extras_msg(extras):
- """
- Create an error message for extra items or properties.
-
- """
-
- if len(extras) == 1:
- verb = "was"
- else:
- verb = "were"
- return ", ".join(repr(extra) for extra in extras), verb
-
-
-def _types_msg(instance, types):
- """
- Create an error message for a failure to match the given types.
-
- If the ``instance`` is an object and contains a ``name`` property, it will
- be considered to be a description of that object and used as its type.
-
- Otherwise the message is simply the reprs of the given ``types``.
-
- """
-
- reprs = []
- for type in types:
- try:
- reprs.append(repr(type["name"]))
- except Exception:
- reprs.append(repr(type))
- return "%r is not of type %s" % (instance, ", ".join(reprs))
-
-
-def _flatten(suitable_for_isinstance):
- """
- isinstance() can accept a bunch of really annoying different types:
- * a single type
- * a tuple of types
- * an arbitrary nested tree of tuples
-
- Return a flattened tuple of the given argument.
-
- """
-
- types = set()
-
- if not isinstance(suitable_for_isinstance, tuple):
- suitable_for_isinstance = (suitable_for_isinstance,)
- for thing in suitable_for_isinstance:
- if isinstance(thing, tuple):
- types.update(_flatten(thing))
- else:
- types.add(thing)
- return tuple(types)
-
-
-def _list(thing):
- """
- Wrap ``thing`` in a list if it's a single str.
-
- Otherwise, return it unchanged.
-
- """
-
- if isinstance(thing, basestring):
- return [thing]
- return thing
-
-
-def _unbool(element, true=object(), false=object()):
- """
- A hack to make True and 1 and False and 0 unique for _uniq.
-
- """
-
- if element is True:
- return true
- elif element is False:
- return false
- return element
-
-
-def _uniq(container):
- """
- Check if all of a container's elements are unique.
-
- Successively tries first to rely that the elements are hashable, then
- falls back on them being sortable, and finally falls back on brute
- force.
-
- """
-
- try:
- return len(set(_unbool(i) for i in container)) == len(container)
- except TypeError:
- try:
- sort = sorted(_unbool(i) for i in container)
- sliced = itertools.islice(sort, 1, None)
- for i, j in zip(sort, sliced):
- if i == j:
- return False
- except (NotImplementedError, TypeError):
- seen = []
- for e in container:
- e = _unbool(e)
- if e in seen:
- return False
- seen.append(e)
- return True
-
-
def validate(instance, schema, cls=None, *args, **kwargs):
if cls is None:
cls = meta_schemas.get(schema.get("$schema", ""), Draft4Validator)
diff --git a/setup.py b/setup.py
index 687d03c..9d78d4f 100644
--- a/setup.py
+++ b/setup.py
@@ -28,7 +28,8 @@ classifiers = [
setup(
name="jsonschema",
version=__version__,
- py_modules=["jsonschema"],
+ packages=["jsonschema"],
+ package_data={'jsonschema': ['schemas/*.json']},
author="Julian Berman",
author_email="Julian@GrayVines.com",
classifiers=classifiers,
diff --git a/tests.py b/test_jsonschema.py
index 7d7d9dc..11d8cd8 100644
--- a/tests.py
+++ b/test_jsonschema.py
@@ -28,11 +28,12 @@ except ImportError:
pypy_version_info = None
from jsonschema import (
- PY3, FormatError, RefResolutionError, SchemaError, UnknownType,
+ FormatError, RefResolutionError, SchemaError, UnknownType,
ValidationError, ErrorTree, Draft3Validator, Draft4Validator,
FormatChecker, RefResolver, ValidatorMixin, draft3_format_checker,
draft4_format_checker, validate,
)
+from jsonschema.compat import PY3
THIS_DIR = os.path.dirname(__file__)
@@ -230,7 +231,7 @@ class TestDraft4(
class RemoteRefResolutionMixin(object):
def setUp(self):
- patch = mock.patch("jsonschema.requests")
+ patch = mock.patch("jsonschema.validators.requests")
requests = patch.start()
requests.get.side_effect = self.resolve
self.addCleanup(patch.stop)
@@ -879,7 +880,7 @@ class TestRefResolver(unittest.TestCase):
ref = "http://bar#baz"
schema = {"baz" : 12}
- with mock.patch("jsonschema.requests") as requests:
+ with mock.patch("jsonschema.validators.requests") as requests:
requests.get.return_value.json.return_value = schema
with self.resolver.resolving(ref) as resolved:
self.assertEqual(resolved, 12)
@@ -889,8 +890,8 @@ class TestRefResolver(unittest.TestCase):
ref = "http://bar#baz"
schema = {"baz" : 12}
- with mock.patch("jsonschema.requests", None):
- with mock.patch("jsonschema.urlopen") as urlopen:
+ with mock.patch("jsonschema.validators.requests", None):
+ with mock.patch("jsonschema.validators.urlopen") as urlopen:
urlopen.return_value.read.return_value = (
json.dumps(schema).encode("utf8"))
with self.resolver.resolving(ref) as resolved:
diff --git a/tox.ini b/tox.ini
index 50e4bba..9f2ead8 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,11 +1,10 @@
[tox]
-envlist = py26, py27, pypy, py32, py33, docs
+envlist = py26, py27, pypy, py32, py33, docs, style
[testenv]
commands =
- py.test -s tests.py
+ py.test -s test_jsonschema.py
{envpython} -m doctest README.rst
- {envpython} -m doctest jsonschema.py
deps =
{[testenv:notpy33]deps}
{[testenv:py33]deps}
@@ -22,8 +21,8 @@ commands =
[testenv:style]
deps = flake8
commands =
- flake8 --max-complexity 10 jsonschema.py
- flake8 tests.py
+ flake8 --max-complexity 10 jsonschema
+ flake8 test_jsonschema.py
[flake8]
ignore = E203,E302,E303,E701,F811
@@ -37,9 +36,8 @@ deps =
[testenv:py33]
commands =
- py.test -s tests.py
+ py.test -s test_jsonschema.py
{envpython} -m doctest README.rst
- {envpython} -m doctest jsonschema.py
sphinx-build -b doctest docs {envtmpdir}/html
deps =
{[testenv:all]deps}