API reference

Validators

class monk.validators.All(specs, default=None, first_is_default=False)[source]

Requires that the value passes all nested validators.

error_class

alias of AtLeastOneFailed

class monk.validators.Any(specs, default=None, first_is_default=False)[source]

Requires that the value passes at least one of nested validators.

error_class

alias of AllFailed

class monk.validators.Anything[source]

Any values passes validation.

class monk.validators.Exists(default=None)[source]

Requires that the value exists. Obviously this only makes sense in special cases like dictionary keys; otherwise there’s simply nothing to validate. Note that this is not a check against None or False.

class monk.validators.IsA(expected_type, default=None)[source]

Requires that the value is an instance of given type.

class monk.validators.HasAttr(attr_name)[source]

Requires that the value has given attribute.

class monk.validators.Equals(expected_value)[source]

Requires that the value equals given expected value.

class monk.validators.Contains(expected_value)[source]

Requires that the value contains given expected value.

class monk.validators.InRange(min=None, max=None, default=NotImplemented)[source]

Requires that the numeric value is in given boundaries.

class monk.validators.Length(min=None, max=None, default=NotImplemented)[source]

Requires that the value length is in given boundaries.

monk.validators.ListOf

alias of ListOfAll

class monk.validators.ListOfAll(validator, default=None)[source]

Requires that the value is a list which items match given validator. Usage:

>>> v = ListOfAll(IsA(int) | IsA(str))

>>> v([123, 'hello'])

>>> v([123, 'hello', 5.5])
Traceback (most recent call last):
...
ValidationError: item #2: must be int or must be str
error_class

alias of AtLeastOneFailed

class monk.validators.ListOfAny(validator, default=None)[source]

Same as ListOfAll but tolerates invalid items as long as there is at least one valid among them.

error_class

alias of AllFailed

class monk.validators.DictOf(pairs)[source]

Requires that the value is a dict which items match given patterns. Usage:

>>> v = DictOf([
...     # key "name" must exist; its value must be a `str`
...     (Equals('name'), IsA(str)),
...     # key "age" may not exist; its value must be an `int`
...     (Equals('age') | ~Exists(), IsA(int)),
...     # there may be other `str` keys with `str` or `int` values
...     (IsA(str), IsA(str) | IsA(int)),
... ])

>>> v({'name': 'John'})

>>> v({'name': 'John', 'age': 25})

>>> v({'name': 'John', 'age': 25.5})
Traceback (most recent call last):
...
DictValueError: 'age' value must be int

>>> v({'name': 'John', 'age': 25, 'note': 'custom field'})

>>> v({'name': 'John', 'age': 25, 'note': 5.5})
Traceback (most recent call last):
...
DictValueError: 'note' value must be str or must be int

Note that this validator supports Exists to mark keys that can be missing.

monk.validators.translate(value)[source]

Translates given schema from “pythonic” syntax to a validator.

Usage:

>>> translate(str)
IsA(str)

>>> translate('hello')
IsA(str, default='hello')
class monk.validators.MISSING[source]

Stub for Exists validator to pass if the value is missing (e.g. for dictionary keys).

Shortcuts

monk.shortcuts.nullable(spec)[source]

Returns a validator which allows the value to be None.

>>> nullable(str) == IsA(str) | Equals(None)
True
monk.shortcuts.optional(spec)[source]

Returns a validator which allows the value to be missing.

>>> optional(str) == IsA(str) | ~Exists()
True
>>> optional('foo') == IsA(str, default='foo') | ~Exists()
True

Note that you should normally opt_key() to mark dictionary keys as optional.

monk.shortcuts.opt_key(spec)[source]

Returns a validator which allows the value to be missing. Similar to optional() but wraps a string in Equals instead of IsA. Intended for dictionary keys.

>>> opt_key(str) == IsA(str) | ~Exists()
True
>>> opt_key('foo') == Equals('foo') | ~Exists()
True
monk.shortcuts.one_of(choices, first_is_default=False, as_rules=False)[source]

A wrapper for Any.

Parameters:as_rulesbool. If False (by default), each element of choices is wrapped in the Equals validator so they are interpreted as literals.

Deprecated since version 0.13: Use Any instead.

Helpers

monk.helpers.validate(spec, value)[source]

Validates given value against given specification. Raises an exception if the value is invalid. Always returns None.

In fact, it’s just a very thin wrapper around the validators. These three expressions are equal:

IsA(str)('foo')
translate(str)('foo')
validate(str, 'foo')
Spec :a validator instance or any value digestible by translate().
Value :any value including complex structures.

Can raise:

MissingKey
if a dictionary key is in the spec but not in the value. This applies to root and nested dictionaries.
InvalidKey
if a dictionary key is the value but not not in the spec.
StructureSpecificationError
if errors were found in spec.
monk.helpers.walk_dict(data)[source]

Generates pairs (keys, value) for each item in given dictionary, including nested dictionaries. Each pair contains:

keys
a tuple of 1..n keys, e.g. ('foo',) for a key on root level or ('foo', 'bar') for a key in a nested dictionary.
value
the value of given key or None if it is a nested dictionary and therefore can be further unwrapped.

Data manipulation

monk.manipulation.merge_defaults(spec, value)[source]

Returns a copy of value recursively updated to match the spec:

  • New values are added whenever possible (including nested ones).
  • Existing values are never changed or removed.
    • Exception: container values (lists, dictionaries) may be populated; see respective merger functions for details.

The result may not pass validation against the spec in the following cases:

  1. a required value is missing and the spec does not provide defaults;
  2. an existing value is invalid.

The business logic is as follows:

  • if value is empty, use default value from spec;
  • if value is present or spec has no default value:
    • if spec datatype is present as a key in mergers, use the respective merger function to obtain the value;
    • if no merger is assigned to the datatype, use fallback function.

See documentation on concrete merger functions for further details.

Spec :A “natural” or “verbose” spec.
Value :The value to merge into the spec.

Examples:

>>> merge_defaults('foo', None)
'foo'
>>> merge_defaults('foo', 'bar')
'bar'
>>> merge_defaults({'a': 'foo'}, {})
{'a': 'foo'}
>>> merge_defaults({'a': [{'b': 123}]},
...                {'a': [{'b': None},
...                       {'x': 0}]})
{'a': [{'b': 123}, {'b': 123, 'x': 0}]}
monk.manipulation.normalize_to_list(value)[source]

Converts given value to a list as follows:

  • [x][x]
  • x[x]
monk.manipulation.normalize_list_of_dicts(value, default_key, default_value=<class monk.manipulation.UNDEFINED at 0x7f2017694460>)[source]

Converts given value to a list of dictionaries as follows:

  • [{...}][{...}]
  • {...}[{...}]
  • 'xyz'[{default_key: 'xyz'}]
  • None[{default_key: default_value}] (if specified)
  • None[]
Parameters:default_value – only Unicode, i.e. str in Python 3.x and only unicode in Python 2.x

Modeling

DB-agnostic helpers to build powerful ODMs.

class monk.modeling.DotExpandedDictMixin[source]

Makes the dictionary dot-expandable by exposing dictionary members via __getattr__ and __setattr__ in addition to __getitem__ and __setitem__. For example, this is the default API:

data = {'foo': {'bar': 0 } }
print data['foo']['bar']
data['foo']['bar'] = 123

This mixin adds the following API:

print data.foo.bar
data.foo.bar = 123

Nested dictionaries are converted to dot-expanded ones on adding.

class monk.modeling.TypedDictReprMixin[source]

Makes repr(self) depend on unicode(self).

class monk.modeling.StructuredDictMixin[source]

A dictionary with structure specification and validation.

structure

The document structure specification. For details see monk.shortcuts.validate().

Exceptions

exception monk.errors.AllFailed[source]

Raised when at least one validator was expected to pass but none did.

exception monk.errors.AtLeastOneFailed[source]

Raised when all validators were expected to pas but at least one didn’t.

exception monk.errors.CombinedValidationError[source]

Raised when a combination of specs has failed validation.

exception monk.errors.DictValueError[source]

Raised when dictionary value fails validation. Used to detect nested errors in order to format the human-readable messages unambiguously.

exception monk.errors.InvalidKeys[source]

Raised whan the value dictionary contains an unexpected key.

exception monk.errors.MissingKeys[source]

Raised when a required dictionary key is missing from the value dict.

exception monk.errors.NoDefaultValue[source]

Raised when the validator could not produce a default value.

exception monk.errors.StructureSpecificationError[source]

Raised when malformed document structure is detected.

exception monk.errors.ValidationError[source]

Raised when a document or its part cannot pass validation.

MongoDB integration

This module combines Monk’s modeling and validation capabilities with MongoDB.

Declaring indexes

Let’s declare a model with indexes:

from monk.mongo import Document

class Item(Document):
    structure = dict(text=unicode, slug=unicode)
    indexes = dict(text=None, slug=dict(unique=True))

Now create a model instance:

item = Item(text=u'foo', slug=u'bar')

Save it and make sure the indexes are created:

item.save(db)

The last line is roughly equivalent to:

collection = db[item.collection]
collection.ensure_index('text')
collection.ensure_index('slug', unique=True)
collection.save(dict(item))  # also validation, transformation, etc.
class monk.mongo.Document(*args, **kwargs)[source]

A structured dictionary that is bound to MongoDB and supports dot notation for access to items.

Inherits features from:

  • dict (builtin),
  • TypedDictReprMixin,
  • DotExpandedDictMixin,
  • StructuredDictMixin and
  • MongoBoundDictMixin.
class monk.mongo.MongoBoundDictMixin[source]

Adds MongoDB-specific features to the dictionary.

collection

Collection name.

indexes

(TODO)

classmethod find(db, *args, **kwargs)[source]

Returns a MongoResultSet object.

Example:

items = Item.find(db, {'title': u'Hello'})

Note

The arguments are those of pymongo collection’s find method. A frequent error is to pass query key/value pairs as keyword arguments. This is wrong. In most cases you will want to pass a dictionary (“query spec”) as the first positional argument.

get_id()[source]

Returns object id or None.

classmethod get_one(db, *args, **kwargs)[source]

Returns an object that corresponds to given query or None.

Example:

item = Item.get_one(db, {'title': u'Hello'})
get_ref()[source]

Returns a DBRef for this object or None.

id[source]

Returns object id or None.

remove(db)[source]

Removes the object from given database. Usage:

item = Item.get_one(db)
item.remove(db)

Collection name is taken from MongoBoundDictMixin.collection.

save(db)[source]

Saves the object to given database. Usage:

item = Item(title=u'Hello')
item.save(db)

Collection name is taken from MongoBoundDictMixin.collection.

class monk.mongo.MongoResultSet(cursor, wrapper)[source]

A wrapper for pymongo cursor that wraps each item using given function or class.

Warning

This class does not introduce caching. Iterating over results exhausts the cursor.

ids()[source]

Returns a generator with identifiers of objects in set. These expressions are equivalent:

ids = (item.id for item in result_set)

ids = result_set.ids()

Warning

This method exhausts the cursor, so an attempt to iterate over results after calling this method will fail. The results are not cached.