Source code for kim.role

# kim/roles.py
# Copyright (C) 2014-2015 the Kim authors and contributors
# <see AUTHORS file>
#
# This module is part of Kim and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php

from kim.exception import RoleError


[docs]class Role(set): """Roles are a fundamental feature of Kim. It's very common to need to provide a different view of your data or to only require a selection of fields when marshaling data. ``Roles`` in Kim allow users to shape their data at runtime in a simple yet flexible manner. ``Roles`` are added to your :py:class:`~.Mapper` declarations using the ``__roles__`` attribute. Usage:: from kim import Mapper, whitelist, field class UserMapper(Mapper): __type__ = User id = field.Integer(read_only=True) name = field.String(required=True) company = field.Nested('myapp.mappers.CompanyMapper') __roles__ = { 'id_only': whitelist('id') } """ def __init__(self, *args, **kwargs): """initialise a new :class:`Role`. :param whitelist: pass a boolean indicating whether this role is a whitelist """ self.whitelist = kwargs.pop('whitelist', True) super(Role, self).__init__(args) @property def fields(self): """return an iterable containing all the field names defined in this role. :rtype: list :returns: iterable of field names """ return [k for k in self]
[docs] def __contains__(self, field_name): """overloaded membership test that inverts the check depending on wether the role is a whitelist or blacklist. If the role is defined as whitelist=True the normal membership test is applied ie:: >>> 'name' in whitelist('name') True For blacklist the test is flipped as we are aiming to ensure the field name is not present in the role:: >>> 'other_name' in blacklist('name') True >>> 'name' in blacklist('name') False :param field_name: name of a field to test for membership :rtype: boolean :returns: boolean indicating wether field_name is found in the role """ if self.whitelist: return super(Role, self).__contains__(field_name) else: return not super(Role, self).__contains__(field_name)
[docs] def __or__(self, other): """Override handling of producing the union of two Roles to provide native support for merging whitelist and blacklist roles correctly. This overloading allows users to produce the union of two roles that may, on one side, want to allow fields and on the other exclude them. Usage:: >>> from kim.role import whitelist, blacklist >>> my_role = whitelist('foo', 'bar') | blacklist('foo', 'baz') >>> my_role Role('bar') :param other: another instance of :class:`kim.role.Role` :raises: :class:`kim.exception.RoleError` :rtype: :class:`kim.role.Role` :returns: a new :class:`kim.role.Role` containng the set of field names """ if not isinstance(other, Role): raise RoleError('union of built in types is not supported with roles') whitelist = True if self.whitelist and other.whitelist: # both roles are whitelists, return the union of both sets result = super(Role, self).__or__(other) elif self.whitelist and not other.whitelist: # we need to remove the fields in self(whitelist) # that appear in other(blacklist) result = super(Role, self).__sub__(other) elif not self.whitelist and other.whitelist: # Same as above, except we are keeping the fields from other result = other.__sub__(self) else: # both roles are blacklist, union them and set whitelist=False whitelist = False result = super(Role, self).__or__(other) return Role(*[k for k in result], whitelist=whitelist)
def __and__(self, other): """Override handling of producing the intersection of two Roles to provide native support for merging whitelist and blacklist roles correctly. This overloading allows users to produce the intersection of two roles that may, on one side, want to allow fields and on the other exclude them. .. codeblock:: python >>>from kim.role import whitelist, blacklist >>>my_role = whitelist('foo', 'bar') & blacklist('foo', 'baz') >>>my_role Role('bar') :param other: another instance of :py:class:``.Role`` :raises: :py:class:`.RoleError`` :rtype: :py:class:``.Role`` :returns: a new :py:class:``.Role`` containng the set of field names """ if not isinstance(other, Role): raise RoleError('intersection of built types is ' 'not supported with roles') whitelist = True if self.whitelist and other.whitelist: # both roles are whitelists, return the union of both sets result = super(Role, self).__and__(other) elif self.whitelist and not other.whitelist: # we need to remove the fields in self(whitelist) # that appear in other(blacklist) result = super(Role, self).__sub__(other) elif not self.whitelist and other.whitelist: # Same as above, except we are keeping the fields from other result = other.__sub__(self) else: # both roles are blacklist, union them and set whitelist=False whitelist = False result = super(Role, self).__or__(other) return Role(*[k for k in result], whitelist=whitelist)
[docs]class whitelist(Role): """ Whitelists are roles that define a list of fields that are permitted for inclusion when marhsaling or serializing. For example, a whitelist role called ``id_only`` that contains the field name ``id`` instructs kim that whenever the ``id_only`` role is used **only** the ``id`` field should be considered in the input/output data. Usage:: from kim import whitelist id_only_role = whitelist('id') class IdMixin(object): id = fields.Integer(read_only=True) __roles__ = { 'id_only': id_only } """ def __init__(self, *args, **kwargs): self.whitelist = True kwargs['whitelist'] = True super(whitelist, self).__init__(*args, **kwargs)
[docs]class blacklist(Role): """ Blacklists are role that act in the opposite manner to whitelists. They define a list of fields that should not be used when marshaling and serializing data. A blacklist role named ``id_less`` that contained the field name ``id`` would instruct kim that every field defined on the mapper should be considered except ``id``. Usage:: from kim import whitelist class UserMapper(Mapper): id_less_role = blacklist('id') __roles__ = { 'id_less': blacklist('id') } """ def __init__(self, *args, **kwargs): kwargs['whitelist'] = False super(blacklist, self).__init__(*args, **kwargs)