Source

audrid / audrid / validators.py

Full commit
# coding: utf-8
"""
Document schemes.
"""

from voluptuous import (
    all, 
    any, 
    boolean,
    length, 
    range, 
    required, 
    Schema,
    Invalid, 
)

def unique(schema, key='id'):
    """
    Check whether a key's value is unique within a list of dictionaries.

    >>> validate = Schema(unique([dict]))
    >>> validate([{"id" : 1}, {"id" : 1}])
    Traceback (most recent call last):
    ...
    InvalidList: duplicate <id> detected
    
    >>> validate([{"id" : 1}, {"x" : 1}, {"y" : 1}])
    [{'id': 1}, {'x': 1}, {'y': 1}]

    >>> validate([{"id" : 1}, {"id" : 2}])
    [{'id': 1}, {'id': 2}]
    """
    def f(v):
        uniq, ctr = set(), 0
        for item in v:
            if key in item:
                uniq.add(item.get(key, None))
                ctr += 1
        if len(uniq) < ctr:
            raise Invalid('duplicate <%s> detected' % key)
        return schema(v)
    schema = Schema(schema)
    return f

options = Schema({
    'case_sensititive' : boolean(),
})

cloze = Schema({
    required('kind') : 'cloze',
    'options' : dict,
    required('id'): all(unicode, length(min=6, max=10)),
    required('task'): all(unicode, length(min=10, max=65535)),    
    required('text'): unicode,
    required('gaps'): dict,
    required('answer'): dict,
})

text = Schema({
    required('kind') : 'text',
    'options' : dict,
    required('id'): all(unicode, length(min=6, max=10)),
    required('task'): all(unicode, length(min=10, max=65535)),    
    required('answer'): unicode,
})

single = Schema({
    required('kind') : 'single',
    'options' : dict,    
    required('id'): all(unicode, length(min=6, max=10)),
    required('task'): all(unicode, length(min=10, max=65535)),
    required('answer'): unicode,
})

choice = Schema({
    required('id'): all(unicode, length(min=1, max=10)),
    required('value'): unicode,
    required('correct'): boolean(),
})

multiple_choice = Schema({
    required('kind') : 'mc',
    'options' : dict,
    required('id'): all(unicode, length(min=6, max=10)),
    required('task'): all(unicode, length(min=10, max=65535)),
    required('choices'): [choice],
    required('answer'): list,
})

mapping = Schema({
    required('kind') : 'mapping',
    'options' : dict,
    required('id'): all(unicode, length(min=6, max=10)),
    required('task'): all(unicode, length(min=10, max=65535)),
    required('mapping'): dict,
    required('answer'): dict,
})

task = Schema(any(mapping, multiple_choice, single, text, cloze))

pool = Schema({
    required('id'): all(unicode, length(min=2, max=12)),
    required('tasks'): unique([any(
        cloze,
        mapping,
        multiple_choice,
        single,
        text,
    )]),
})

trial = Schema({
    required('id'): all(unicode, length(min=6, max=12)),
    required('user') : int,
    required('pool') : pool,
})

# for the wire
exam = Schema({
    required('pool_id'): all(unicode, length(min=2, max=12)),
    required('name'): unicode,
    'pool_version': int,
    'description' : unicode,
    'duration': int,
})

audit = Schema({
    required('user_id'): int,
    required('exam_id'): int,
    'status': unicode,
})

if __name__ == '__main__':
    # Examples
    t = mapping({
        "kind"      : u"mapping", 
        "id"        : u"country1", 
        "task"      : u"Assign capitals to countries!", 
        "answer"    : {},
        "mapping"   : {
            "Berlin" : u"Germany",
            "Paris"  : u"France",
            "Budapest" : u"Hungary",
        },
    })

    u = text({
        "kind"      : u"text", 
        "id"        : u"text11", 
        "task"      : u"Write a poem!", 
        "answer"    : u"",
    })

    p = pool({
        "id" : u"geo", 
        "tasks" : [t, u]
    })

    t = trial({
        "id" : u"67s9hp",
        "user" : 1,
        "pool" : p
    })

    import doctest
    doctest.testmod()