diff --git a/.travis.yml b/.travis.yml index 50b77fb..aaf6a24 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,12 +18,9 @@ cache: install: pip install codecov tox env: - - TOX_ENV=py26 - TOX_ENV=py27 - - TOX_ENV=py33 - TOX_ENV=py34 - TOX_ENV=py35 - - TOX_ENV=pypy - TOX_ENV=coverage - TOX_ENV=pep8 diff --git a/README.rst b/README.rst index dd4dbee..3d4cc79 100644 --- a/README.rst +++ b/README.rst @@ -162,6 +162,23 @@ Dropping the details, ``Use`` is basically: except Exception as e: raise SchemaError('%r raised %r' % (self._callable.__name__, e)) + +Sometimes you need to transform and validate part of data, but keep original data unchanged. +``Const`` helps to keep your data safe: + +.. code:: python + + >> from schema import Use, Const, And, Schema + + >> from datetime import datetime + + >> is_future = lambda date: datetime.now() > date + + >> to_json = lambda v: {"timestamp": v} + + >> Schema(And(Const(And(Use(datetime.fromtimestamp), is_future)), Use(to_json))).validate(1234567890) + {"timestamp": 1234567890} + Now you can write your own validation-aware classes and data types. Lists, similar containers diff --git a/schema.py b/schema.py index bc5b398..7bd91a5 100644 --- a/schema.py +++ b/schema.py @@ -6,7 +6,7 @@ __version__ = '0.6.6' __all__ = ['Schema', - 'And', 'Or', 'Regex', 'Optional', 'Use', 'Forbidden', + 'And', 'Or', 'Regex', 'Optional', 'Use', 'Forbidden', 'Const', 'SchemaError', 'SchemaWrongKeyError', 'SchemaMissingKeyError', @@ -372,6 +372,12 @@ def __init__(self, *args, **kwargs): self.key = self._schema +class Const(Schema): + def validate(self, data): + super(Const, self).validate(data) + return data + + def _callable_str(callable_): if hasattr(callable_, '__name__'): return callable_.__name__ diff --git a/test_schema.py b/test_schema.py index 231afcf..f58eb66 100644 --- a/test_schema.py +++ b/test_schema.py @@ -1,5 +1,6 @@ from __future__ import with_statement from collections import defaultdict, namedtuple +from functools import partial from operator import methodcaller import os import re @@ -8,7 +9,7 @@ from pytest import raises -from schema import (Schema, Use, And, Or, Regex, Optional, +from schema import (Schema, Use, And, Or, Regex, Optional, Const, SchemaError, SchemaWrongKeyError, SchemaMissingKeyError, SchemaUnexpectedTypeError, SchemaForbiddenKeyError, Forbidden) @@ -76,6 +77,28 @@ def test_or(): with SE: Or().validate(2) +def test_test(): + def unique_list(_list): + return len(_list) == len(set(_list)) + + def dict_keys(key, _list): + return list(map(lambda d: d[key], _list)) + + schema = ( + Schema( + Const( + And(Use(partial(dict_keys, "index")), unique_list)))) + data = [ + {"index": 1, "value": "foo"}, + {"index": 2, "value": "bar"}] + assert schema.validate(data) == data + + bad_data = [ + {"index": 1, "value": "foo"}, + {"index": 1, "value": "bar"}] + with SE: schema.validate(bad_data) + + def test_regex(): # Simple case: validate string assert Regex(r'foo').validate('afoot') == 'afoot'