Table of Contents
jsonweb.schema
¶
Declarative¶
jsonweb.schema
provides a layer of validation before json.decode
returns your object instances. It can also simply be used to validate the
resulting python data structures returned from json.loads()
. It’s main
use is through a declarative style api. Here is an example of validating the
structure of a python dict:
>>>
>>> from jsonweb.schema import ObjectSchema, ValidationError
>>> from jsonweb.validators import String
>>> class PersonSchema(ObjectSchema):
... first_name = String()
... last_name = String()
>>> try:
... PersonSchema().validate({"first_name": "shawn"})
... except ValidationError, e:
... print e.errors
{"last_name": "Missing required parameter."}
Validating plain old python data structures is fine, but the more interesting exercise is tying a schema to a class definition:
>>> from jsonweb.decode import from_object, loader
>>> from jsonweb.schema import ObjectSchema, ValidationError
>>> from jsonweb.validators import String, Integer, EnsureType
>>> class PersonSchema(ObjectSchema):
... id = Integer()
... first_name = String()
... last_name = String()
... gender = String(optional=True)
... job = EnsureType("Job")
You can make any field optional by setting optional
to True
.
Warning
The field is only optional at the schema level. If you’ve bound a schema
to a class via from_object()
and the underlying
class requires that field a ObjectAttributeError
will be raised if missing.
As you can see its fine to pass a class name as a string, which we have done
for the Job
class above. We must later define Job
and
decorate it with from_object()
>>> class JobSchema(ObjectSchema):
... id = Integer()
... title = String()
>>> @from_object(schema=JobSchema)
... class Job(object):
... def __init__(self, id, title):
... self.id = id
... self.title = title
>>> @from_object(schema=PersonSchema)
... class Person(object):
... def __init__(self, first_name, last_name, job, gender=None):
... self.first_name = first_name
... self.last_name = last_name
... self.gender = gender
... self.job = job
... def __str__(self):
... return '<Person name="%s" job="{0}">'.format(
... " ".join((self.first_name, self.last_name)),
... self.job.title
... )
>>> person_json = '''
... {
... "__type__": "Person",
... "id": 1,
... "first_name": "Bob",
... "last_name": "Smith",
... "job": {"__type__": "Job", "id": 5, "title": "Police Officer"},
... }'''
...
>>> person = loader(person_json)
>>> print person
<Person name="Bob" job="Police Officer">
Non-Declarative¶
New in version 0.8.1.
Use the staticmethod ObjectSchema.create()
to build object schemas in
a non declarative style. Handy for validating dicts with string keys that
are not valid python identifiers (e.g “first-name”):
MySchema = ObjectSchema.create("MySchema", {
"first-name": String(),
"last-name": String(optional=True)
})
jsonweb.validators
¶
-
class
jsonweb.validators.
BaseValidator
(optional=False, nullable=False, default=None, reason_code=None)¶ Abstract base validator which all
JsonWeb
validators should inherit from. Out of the boxJsonWeb
comes with a dozen or so validators.All validators will override
BaseValidator._validate()
method which should accept an object and return the passed in object or raise aValidationError
if validation failed.Note
You are not required to return the exact passed in object. You may for instance want to transform the object in some way. This is exactly what
DateTime
does.-
__init__
(optional=False, nullable=False, default=None, reason_code=None)¶ All validators that inherit from
BaseValidator
should passoptional
,nullable
anddefault
as explicit kw arguments or**kw
.Parameters: - optional – Is the item optional?
- nullable – Can the item’s value can be None?
- default – A default value for this item.
- reason_code – Failure reason_code that is passed to any
ValidationError
raised from this instance.
-
-
class
jsonweb.validators.
String
(min_len=None, max_len=None, **kw)¶ Validates something is a string
>>> String().validate("foo") ... 'foo' >>> String().validate(1) Traceback (most recent call last): ... ValidationError: Expected str got int instead.
Specify a maximum length
>>> String(max_len=3).validate("foobar") Traceback (most recent call last): ... ValidationError: String exceeds max length of 3.
Specify a minimum length
>>> String(min_len=3).validate("fo") Traceback (most recent call last): ... ValidationError: String must be at least length 3.
-
class
jsonweb.validators.
Regex
(regex, **kw)¶ New in version 0.6.3: Validates a string against a regular expression ::
>>> Regex(r"^foo").validate("barfoo") Traceback (most recent call last): ... ValidationError: String does not match pattern '^foo'.
-
class
jsonweb.validators.
Number
(**kw)¶ Validates something is a number
>>> Number().validate(1) ... 1 >>> Number().validate(1.1) >>> 1.1 >>> Number().validate("foo") Traceback (most recent call last): ... ValidationError: Expected number got int instead.
-
class
jsonweb.validators.
Integer
(**kw)¶ Validates something in an integer
-
class
jsonweb.validators.
Float
(**kw)¶ Validates something is a float
-
class
jsonweb.validators.
Boolean
(**kw)¶ Validates something is a Boolean (True/False)
-
class
jsonweb.validators.
DateTime
(format='%Y-%m-%d %H:%M:%S', **kw)¶ Validates that something is a valid date/datetime string and turns it into a
datetime.datetime
instance>>> DateTime().validate("2010-01-02 12:30:00") ... datetime.datetime(2010, 1, 2, 12, 30) >>> DateTime().validate("2010-01-02 12:300") Traceback (most recent call last): ... ValidationError: time data '2010-01-02 12:300' does not match format '%Y-%m-%d %H:%M:%S'
The default datetime format is
%Y-%m-%d %H:%M:%S
. You can specify your own>>> DateTime("%m/%d/%Y").validate("01/02/2010") ... datetime.datetime(2010, 1, 2, 0, 0)
-
class
jsonweb.validators.
EnsureType
(_type, type_name=None, **kw)¶ Validates something is a certain type
>>> class Person(object): ... pass >>> EnsureType(Person).validate(Person()) ... <Person> >>> EnsureType(Person).validate(10) Traceback (most recent call last): ... ValidationError: Expected Person got int instead.
-
class
jsonweb.validators.
List
(validator, **kw)¶ Validates a list of things. The List constructor accepts a validator and each item in the list will be validated against it
>>> List(Integer).validate([1,2,3,4]) ... [1,2,3,4] >>> List(Integer).validate(10) Traceback (most recent call last): ... ValidationError: Expected list got int instead.
Since
ObjectSchema
is also a validator we can do this>>> class PersonSchema(ObjectSchema): ... first_name = String() ... last_name = String() ... >>> List(PersonSchema).validate([ ... {"first_name": "bob", "last_name": "smith"}, ... {"first_name": "jane", "last_name": "smith"} ... ])
-
class
jsonweb.validators.
Dict
(validator, key_validator=None, **kw)¶ New in version 0.8.
Validates a dict of things. The Dict constructor accepts a validator and each value in the dict will be validated against it
>>> Dict(Number).validate({'foo': 1}) ... {'foo': 1} >>> Dict(Number).validate({'foo': "abc"}) Traceback (most recent call last): ... ValidationError: Error validating dict.
In order see what part of the dict failed validation we must dig deeper into the exception:
>>> str(e.errors["foo"]) ... 'Expected number got str instead.'
Dict
also accepts an optionalkey_validator
, which must be a subclass ofString
:validator = Dict(Number, key_validator=Regex(r'^[a-z]{2}_[A-Z]{2}$')) try: validator.validate({"en-US": 1}) except ValidationError as e: print(e.errors["en-US"]) print(e.errors["en-US"].reason_code) # output # String does not match pattern '^[a-z]{2}_[A-Z]{2}$'. # invalid_dict_key
-
class
jsonweb.validators.
OneOf
(*values, **kw)¶ New in version 0.6.4: Validates something is a one of a list of allowed values::
>>> OneOf("a", "b", "c").validate(1) Traceback (most recent call last): ... ValidationError: Expected one of (a, b, c) got 1 instead.
-
class
jsonweb.validators.
SubSetOf
(super_set, **kw)¶ New in version 0.6.4: Validates a list is subset of another list::
>>> SubSetOf([1, 2, 3, 4]).validate([1, 4]) ... [1, 4] >>> SubSetOf([1, 2, 3, 4]).validate([1,5]) Traceback (most recent call last): ... ValidationError: [1, 5] is not a subset of [1, 2, 3, 4].
ValidationErrors¶
-
class
jsonweb.validators.
ValidationError
(reason, reason_code=None, errors=None, **extras)¶ Raised from
JsonWeb
validators when validation of an object fails.-
__init__
(reason, reason_code=None, errors=None, **extras)¶ Parameters: - reason – A nice message describing what was not valid
- reason_code – programmatic friendly reason code
- errors – A
list
ordict
of nestedValidationError
- extras – Any extra info about the error you want to convey
-