Skip to content

Instantly share code, notes, and snippets.

@andreypopp
Created May 28, 2011 10:06
Show Gist options
  • Save andreypopp/996765 to your computer and use it in GitHub Desktop.
Save andreypopp/996765 to your computer and use it in GitHub Desktop.
""" Contract2."""
class ValidationError(TypeError):
pass
class Type(object):
def validate(self, value):
raise NotImplementedError()
class Int(Type):
def validate(self, value):
if not isinstance(value, (int, long)):
raise ValidationError()
class String(Type):
def validate(self, value):
if not isinstance(value, basestring):
raise ValidationError()
class Node(object):
""" Node represents structural properties of value."""
def validate(self, value):
raise NotImplementedError()
class Value(Node):
""" Value represents type as structural entity.
>>> schema = Value(Int)
>>> schema.validate(1)
>>> schema.validate("1")
Traceback (most recent call last):
...
ValidationError
"""
def __init__(self, typ):
if isinstance(typ, type) and issubclass(typ, Type):
typ = typ()
self.type = typ
def validate(self, value):
self.type.validate(value)
class Sequence(Node):
""" Sequence represent iterable sequence.
>>> schema = Sequence(Int)
>>> schema.validate([1, 2, 3])
>>> schema.validate([1, "2", 3])
Traceback (most recent call last):
...
ValidationError
"""
def __init__(self, node):
if isinstance(node, type) and issubclass(node, Type):
node = node()
if isinstance(node, Type):
node = Value(node)
self.node = node
def validate(self, value):
if not hasattr(value, "__iter__"):
raise ValidationError("%r is not iterable" % value)
for item in value:
self.node.validate(item)
class Optional(Node):
""" Value, which is optional.
This kind of value behaves exactly like ``Value``, but treated differently
by containers::
>>> schema = Optional(Int)
>>> schema.validate(1)
>>> schema.validate("1")
Traceback (most recent call last):
...
ValidationError
"""
def __init__(self, node):
if isinstance(node, type) and issubclass(node, Type):
node = node()
if isinstance(node, Type):
node = Value(node)
self.node = node
def validate(self, value):
self.node.validate(value)
class Mapping(Node):
""" Mapping represents disrete mapping, such as dictionary.
>>> schema = Mapping(a=Optional(Int), b=String)
>>> schema.validate({"a": 1, "b": "string"})
>>> schema.validate({"b": "string"})
>>> schema.validate({"a": 1})
Traceback (most recent call last):
...
ValidationError: b is missing
>>> schema.validate({"b": 1})
Traceback (most recent call last):
...
ValidationError
"""
def __init__(self, **nodes):
for name, node in nodes.items():
if isinstance(node, type) and issubclass(node, Type):
node = node()
if isinstance(node, Type):
node = Value(node)
nodes[name] = node
self.nodes = nodes
def validate(self, value):
if not hasattr(value, "__getitem__"):
raise ValidationError("%r is not indexable" % value)
for name, node in self.nodes.items():
try:
node_value = value[name]
except KeyError:
if not isinstance(node, Optional):
raise ValidationError("%s is missing" % name)
else:
node.validate(node_value)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment