You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			383 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			ReStructuredText
		
	
		
		
			
		
	
	
			383 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			ReStructuredText
		
	
| 
								 
											9 years ago
										 
									 | 
							
								Schema validation just got Pythonic
							 | 
						||
| 
								 | 
							
								===============================================================================
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								**schema** is a library for validating Python data structures, such as those
							 | 
						||
| 
								 | 
							
								obtained from config-files, forms, external services or command-line
							 | 
						||
| 
								 | 
							
								parsing, converted from JSON/YAML (or something else) to Python data-types.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. image:: https://secure.travis-ci.org/keleshev/schema.png?branch=master
							 | 
						||
| 
								 | 
							
								    :target: https://travis-ci.org/keleshev/schema
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. image:: https://img.shields.io/codecov/c/github/keleshev/schema.svg
							 | 
						||
| 
								 | 
							
								    :target: http://codecov.io/github/keleshev/schema
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Example
							 | 
						||
| 
								 | 
							
								----------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Here is a quick example to get a feeling of **schema**, validating a list of
							 | 
						||
| 
								 | 
							
								entries with personal information:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> from schema import Schema, And, Use, Optional
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> schema = Schema([{'name': And(str, len),
							 | 
						||
| 
								 | 
							
								    ...                   'age':  And(Use(int), lambda n: 18 <= n <= 99),
							 | 
						||
| 
								 | 
							
								    ...                   Optional('sex'): And(str, Use(str.lower),
							 | 
						||
| 
								 | 
							
								    ...                                        lambda s: s in ('male', 'female'))}])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> data = [{'name': 'Sue', 'age': '28', 'sex': 'FEMALE'},
							 | 
						||
| 
								 | 
							
								    ...         {'name': 'Sam', 'age': '42'},
							 | 
						||
| 
								 | 
							
								    ...         {'name': 'Sacha', 'age': '20', 'sex': 'Male'}]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> validated = schema.validate(data)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> assert validated == [{'name': 'Sue', 'age': 28, 'sex': 'female'},
							 | 
						||
| 
								 | 
							
								    ...                      {'name': 'Sam', 'age': 42},
							 | 
						||
| 
								 | 
							
								    ...                      {'name': 'Sacha', 'age' : 20, 'sex': 'male'}]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If data is valid, ``Schema.validate`` will return the validated data
							 | 
						||
| 
								 | 
							
								(optionally converted with `Use` calls, see below).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If data is invalid, ``Schema`` will raise ``SchemaError`` exception.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Installation
							 | 
						||
| 
								 | 
							
								-------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Use `pip <http://pip-installer.org>`_ or easy_install::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    pip install schema
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Alternatively, you can just drop ``schema.py`` file into your project—it is
							 | 
						||
| 
								 | 
							
								self-contained.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								- **schema** is tested with Python 2.6, 2.7, 3.2, 3.3 and PyPy.
							 | 
						||
| 
								 | 
							
								- **schema** follows `semantic versioning <http://semver.org>`_.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								How ``Schema`` validates data
							 | 
						||
| 
								 | 
							
								-------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Types
							 | 
						||
| 
								 | 
							
								~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If ``Schema(...)`` encounters a type (such as ``int``, ``str``, ``object``,
							 | 
						||
| 
								 | 
							
								etc.), it will check if the corresponding piece of data is an instance of that type,
							 | 
						||
| 
								 | 
							
								otherwise it will raise ``SchemaError``.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> from schema import Schema
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Schema(int).validate(123)
							 | 
						||
| 
								 | 
							
								    123
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Schema(int).validate('123')
							 | 
						||
| 
								 | 
							
								    Traceback (most recent call last):
							 | 
						||
| 
								 | 
							
								    ...
							 | 
						||
| 
								 | 
							
								    SchemaUnexpectedTypeError: '123' should be instance of 'int'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Schema(object).validate('hai')
							 | 
						||
| 
								 | 
							
								    'hai'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Callables
							 | 
						||
| 
								 | 
							
								~~~~~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If ``Schema(...)`` encounters a callable (function, class, or object with
							 | 
						||
| 
								 | 
							
								``__call__`` method) it will call it, and if its return value evaluates to
							 | 
						||
| 
								 | 
							
								``True`` it will continue validating, else—it will raise ``SchemaError``.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> import os
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Schema(os.path.exists).validate('./')
							 | 
						||
| 
								 | 
							
								    './'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Schema(os.path.exists).validate('./non-existent/')
							 | 
						||
| 
								 | 
							
								    Traceback (most recent call last):
							 | 
						||
| 
								 | 
							
								    ...
							 | 
						||
| 
								 | 
							
								    SchemaError: exists('./non-existent/') should evaluate to True
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Schema(lambda n: n > 0).validate(123)
							 | 
						||
| 
								 | 
							
								    123
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Schema(lambda n: n > 0).validate(-12)
							 | 
						||
| 
								 | 
							
								    Traceback (most recent call last):
							 | 
						||
| 
								 | 
							
								    ...
							 | 
						||
| 
								 | 
							
								    SchemaError: <lambda>(-12) should evaluate to True
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								"Validatables"
							 | 
						||
| 
								 | 
							
								~~~~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If ``Schema(...)`` encounters an object with method ``validate`` it will run
							 | 
						||
| 
								 | 
							
								this method on corresponding data as ``data = obj.validate(data)``. This method
							 | 
						||
| 
								 | 
							
								may raise ``SchemaError`` exception, which will tell ``Schema`` that that piece
							 | 
						||
| 
								 | 
							
								of data is invalid, otherwise—it will continue validating.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								An example of "validatable" is ``Regex``, that tries to match a string or a
							 | 
						||
| 
								 | 
							
								buffer with the given regular expression (itself as a string, buffer or
							 | 
						||
| 
								 | 
							
								compiled regex ``SRE_Pattern``):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> from schema import Regex
							 | 
						||
| 
								 | 
							
								    >>> import re
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Regex(r'^foo').validate('foobar')
							 | 
						||
| 
								 | 
							
								    'foobar'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Regex(r'^[A-Z]+$', flags=re.I).validate('those-dashes-dont-match')
							 | 
						||
| 
								 | 
							
								    Traceback (most recent call last):
							 | 
						||
| 
								 | 
							
								    ...
							 | 
						||
| 
								 | 
							
								    SchemaError: Regex('^[A-Z]+$', flags=re.IGNORECASE) does not match 'those-dashes-dont-match'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								For a more general case, you can use ``Use`` for creating such objects.
							 | 
						||
| 
								 | 
							
								``Use`` helps to use a function or type to convert a value while validating it:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> from schema import Use
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Schema(Use(int)).validate('123')
							 | 
						||
| 
								 | 
							
								    123
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Schema(Use(lambda f: open(f, 'a'))).validate('LICENSE-MIT')
							 | 
						||
| 
								 | 
							
								    <open file 'LICENSE-MIT', mode 'a' at 0x...>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Dropping the details, ``Use`` is basically:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    class Use(object):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def __init__(self, callable_):
							 | 
						||
| 
								 | 
							
								            self._callable = callable_
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def validate(self, data):
							 | 
						||
| 
								 | 
							
								            try:
							 | 
						||
| 
								 | 
							
								                return self._callable(data)
							 | 
						||
| 
								 | 
							
								            except Exception as e:
							 | 
						||
| 
								 | 
							
								                raise SchemaError('%r raised %r' % (self._callable.__name__, e))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Now you can write your own validation-aware classes and data types.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Lists, similar containers
							 | 
						||
| 
								 | 
							
								~~~~~~~~~~~~~~~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If ``Schema(...)`` encounters an instance of ``list``, ``tuple``, ``set`` or
							 | 
						||
| 
								 | 
							
								``frozenset``, it will validate contents of corresponding data container
							 | 
						||
| 
								 | 
							
								against schemas listed inside that container:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Schema([1, 0]).validate([1, 1, 0, 1])
							 | 
						||
| 
								 | 
							
								    [1, 1, 0, 1]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Schema((int, float)).validate((5, 7, 8, 'not int or float here'))
							 | 
						||
| 
								 | 
							
								    Traceback (most recent call last):
							 | 
						||
| 
								 | 
							
								    ...
							 | 
						||
| 
								 | 
							
								    SchemaError: Or(<type 'int'>, <type 'float'>) did not validate 'not int or float here'
							 | 
						||
| 
								 | 
							
								    'not int or float here' should be instance of 'float'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Dictionaries
							 | 
						||
| 
								 | 
							
								~~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If ``Schema(...)`` encounters an instance of ``dict``, it will validate data
							 | 
						||
| 
								 | 
							
								key-value pairs:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> d = Schema({'name': str,
							 | 
						||
| 
								 | 
							
								    ...             'age': lambda n: 18 <= n <= 99}).validate({'name': 'Sue', 'age': 28})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> assert d == {'name': 'Sue', 'age': 28}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								You can specify keys as schemas too:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> schema = Schema({str: int,  # string keys should have integer values
							 | 
						||
| 
								 | 
							
								    ...                  int: None})  # int keys should be always None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> data = schema.validate({'key1': 1, 'key2': 2,
							 | 
						||
| 
								 | 
							
								    ...                         10: None, 20: None})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> schema.validate({'key1': 1,
							 | 
						||
| 
								 | 
							
								    ...                   10: 'not None here'})
							 | 
						||
| 
								 | 
							
								    Traceback (most recent call last):
							 | 
						||
| 
								 | 
							
								    ...
							 | 
						||
| 
								 | 
							
								    SchemaError: Key '10' error:
							 | 
						||
| 
								 | 
							
								    None does not match 'not None here'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This is useful if you want to check certain key-values, but don't care
							 | 
						||
| 
								 | 
							
								about other:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> schema = Schema({'<id>': int,
							 | 
						||
| 
								 | 
							
								    ...                  '<file>': Use(open),
							 | 
						||
| 
								 | 
							
								    ...                  str: object})  # don't care about other str keys
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> data = schema.validate({'<id>': 10,
							 | 
						||
| 
								 | 
							
								    ...                         '<file>': 'README.rst',
							 | 
						||
| 
								 | 
							
								    ...                         '--verbose': True})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								You can mark a key as optional as follows:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> from schema import Optional
							 | 
						||
| 
								 | 
							
								    >>> Schema({'name': str,
							 | 
						||
| 
								 | 
							
								    ...         Optional('occupation'): str}).validate({'name': 'Sam'})
							 | 
						||
| 
								 | 
							
								    {'name': 'Sam'}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								``Optional`` keys can also carry a ``default``, to be used when no key in the
							 | 
						||
| 
								 | 
							
								data matches:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> from schema import Optional
							 | 
						||
| 
								 | 
							
								    >>> Schema({Optional('color', default='blue'): str,
							 | 
						||
| 
								 | 
							
								    ...         str: str}).validate({'texture': 'furry'}
							 | 
						||
| 
								 | 
							
								    ...       ) == {'color': 'blue', 'texture': 'furry'}
							 | 
						||
| 
								 | 
							
								    True
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Defaults are used verbatim, not passed through any validators specified in the
							 | 
						||
| 
								 | 
							
								value.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								**schema** has classes ``And`` and ``Or`` that help validating several schemas
							 | 
						||
| 
								 | 
							
								for the same data:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> from schema import And, Or
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Schema({'age': And(int, lambda n: 0 < n < 99)}).validate({'age': 7})
							 | 
						||
| 
								 | 
							
								    {'age': 7}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Schema({'password': And(str, lambda s: len(s) > 6)}).validate({'password': 'hai'})
							 | 
						||
| 
								 | 
							
								    Traceback (most recent call last):
							 | 
						||
| 
								 | 
							
								    ...
							 | 
						||
| 
								 | 
							
								    SchemaError: Key 'password' error:
							 | 
						||
| 
								 | 
							
								    <lambda>('hai') should evaluate to True
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Schema(And(Or(int, float), lambda x: x > 0)).validate(3.1415)
							 | 
						||
| 
								 | 
							
								    3.1415
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Extra Keys
							 | 
						||
| 
								 | 
							
								~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The ``Schema(...)`` parameter ``ignore_extra_keys`` causes validation to ignore extra keys in a dictionary, and also to not return them after validating.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> schema = Schema({'name': str}, ignore_extra_keys=True)
							 | 
						||
| 
								 | 
							
								    >>> schema.validate({'name': 'Sam', 'age': '42'})
							 | 
						||
| 
								 | 
							
								    {'name': 'Sam'}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If you would like any extra keys returned, use ``object: object`` as one of the key/value pairs, which will match any key and any value.
							 | 
						||
| 
								 | 
							
								Otherwise, extra keys will raise a ``SchemaError``.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								User-friendly error reporting
							 | 
						||
| 
								 | 
							
								-------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								You can pass a keyword argument ``error`` to any of validatable classes
							 | 
						||
| 
								 | 
							
								(such as ``Schema``, ``And``, ``Or``, ``Regex``, ``Use``) to report this error
							 | 
						||
| 
								 | 
							
								instead of a built-in one.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> Schema(Use(int, error='Invalid year')).validate('XVII')
							 | 
						||
| 
								 | 
							
								    Traceback (most recent call last):
							 | 
						||
| 
								 | 
							
								    ...
							 | 
						||
| 
								 | 
							
								    SchemaError: Invalid year
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								You can see all errors that occurred by accessing exception's ``exc.autos``
							 | 
						||
| 
								 | 
							
								for auto-generated error messages, and ``exc.errors`` for errors
							 | 
						||
| 
								 | 
							
								which had ``error`` text passed to them.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								You can exit with ``sys.exit(exc.code)`` if you want to show the messages
							 | 
						||
| 
								 | 
							
								to the user without traceback. ``error`` messages are given precedence in that
							 | 
						||
| 
								 | 
							
								case.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								A JSON API example
							 | 
						||
| 
								 | 
							
								-------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Here is a quick example: validation of
							 | 
						||
| 
								 | 
							
								`create a gist <http://developer.github.com/v3/gists/>`_
							 | 
						||
| 
								 | 
							
								request from github API.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> gist = '''{"description": "the description for this gist",
							 | 
						||
| 
								 | 
							
								    ...            "public": true,
							 | 
						||
| 
								 | 
							
								    ...            "files": {
							 | 
						||
| 
								 | 
							
								    ...                "file1.txt": {"content": "String file contents"},
							 | 
						||
| 
								 | 
							
								    ...                "other.txt": {"content": "Another file contents"}}}'''
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> from schema import Schema, And, Use, Optional
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> import json
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> gist_schema = Schema(And(Use(json.loads),  # first convert from JSON
							 | 
						||
| 
								 | 
							
								    ...                          # use basestring since json returns unicode
							 | 
						||
| 
								 | 
							
								    ...                          {Optional('description'): basestring,
							 | 
						||
| 
								 | 
							
								    ...                           'public': bool,
							 | 
						||
| 
								 | 
							
								    ...                           'files': {basestring: {'content': basestring}}}))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> gist = gist_schema.validate(gist)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # gist:
							 | 
						||
| 
								 | 
							
								    {u'description': u'the description for this gist',
							 | 
						||
| 
								 | 
							
								     u'files': {u'file1.txt': {u'content': u'String file contents'},
							 | 
						||
| 
								 | 
							
								                u'other.txt': {u'content': u'Another file contents'}},
							 | 
						||
| 
								 | 
							
								     u'public': True}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Using **schema** with `docopt <http://github.com/docopt/docopt>`_
							 | 
						||
| 
								 | 
							
								-------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Assume you are using **docopt** with the following usage-pattern:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Usage: my_program.py [--count=N] <path> <files>...
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								and you would like to validate that ``<files>`` are readable, and that
							 | 
						||
| 
								 | 
							
								``<path>`` exists, and that ``--count`` is either integer from 0 to 5, or
							 | 
						||
| 
								 | 
							
								``None``.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Assuming **docopt** returns the following dict:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> args = {'<files>': ['LICENSE-MIT', 'setup.py'],
							 | 
						||
| 
								 | 
							
								    ...         '<path>': '../',
							 | 
						||
| 
								 | 
							
								    ...         '--count': '3'}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								this is how you validate it using ``schema``:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. code:: python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> from schema import Schema, And, Or, Use
							 | 
						||
| 
								 | 
							
								    >>> import os
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> s = Schema({'<files>': [Use(open)],
							 | 
						||
| 
								 | 
							
								    ...             '<path>': os.path.exists,
							 | 
						||
| 
								 | 
							
								    ...             '--count': Or(None, And(Use(int), lambda n: 0 < n < 5))})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> args = s.validate(args)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> args['<files>']
							 | 
						||
| 
								 | 
							
								    [<open file 'LICENSE-MIT', mode 'r' at 0x...>, <open file 'setup.py', mode 'r' at 0x...>]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> args['<path>']
							 | 
						||
| 
								 | 
							
								    '../'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> args['--count']
							 | 
						||
| 
								 | 
							
								    3
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								As you can see, **schema** validated data successfully, opened files and
							 | 
						||
| 
								 | 
							
								converted ``'3'`` to ``int``.
							 |