<gh_stars>0
﻿import inspect


class RoleSet(object):

    DEFINE_CONTAINS = 'error: {}\n role {} should define a "contains(self, principal, *extra_info)" method that returns a boolean value'

    def __init__(self, roles):
        self._roles = roles

    def check(self, principal, *extra_info):
        result = True
        def visitor(role):
            if inspect.isclass(role):
                role = role()
            nonlocal result
            try:
                contains = self._contains(role, principal, *extra_info)
                if not contains:
                    result = False
            except (AttributeError, TypeError) as e:
                raise NotImplementedError(RoleSet.DEFINE_CONTAINS.format(e, role))
        self._traverse(self._roles, visitor)
        return result

    def get_msg(self, principal, *extra_info):
        msg = []
        break_it = False
        def visitor(role):
            if inspect.isclass(role):
                role = role()
            nonlocal break_it
            try:
                if not break_it:
                    contains = self._contains(role, principal, *extra_info)
                    if contains:
                        msg.append('{0} contains {1} and {2} AND'
                                   .format(role, principal, extra_info))
                    else:
                        msg.append('{0} DOES NOT contain {1} and {2}'
                                   .format(role, principal, extra_info))
                        break_it = True
            except (AttributeError, TypeError) as e:
                raise NotImplementedError(RoleSet.DEFINE_CONTAINS.format(e, role))
        self._traverse(self._roles, visitor)
        return '\n'.join(msg)

    def _contains(self, role, principal, *extra_info):
        contains = role.contains(principal, *extra_info)
        if not isinstance(contains, bool):
            raise TypeError("{}.'contains' does not return a boolean value".format(role))
        return contains

    def _traverse(self, roles, visitor):
        for role in roles:
            visitor(role)

    @property
    def roles(self):
        return self._roles


class AllowRoleSet(RoleSet):
    pass


class DenyRoleSet(RoleSet):
    pass
﻿import inspect


class RoleSet(object):

    DEFINE_CONTAINS = 'error: {}\n role {} should define a "contains(self, principal, *extra_info)" method that returns a boolean value'

    def __init__(self, roles):
        self._roles = roles

    def check(self, principal, *extra_info):
        result = True
        def visitor(role):
            if inspect.isclass(role):
                role = role()
            nonlocal result
            try:
                contains = self._contains(role, principal, *extra_info)
                if not contains:
                    result = False
            except (AttributeError, TypeError) as e:
                raise NotImplementedError(RoleSet.DEFINE_CONTAINS.format(e, role))
        self._traverse(self._roles, visitor)
        return result

    def get_msg(self, principal, *extra_info):
        msg = []
        break_it = False
        def visitor(role):
            if inspect.isclass(role):
                role = role()
            nonlocal break_it
            try:
                if not break_it:
                    contains = self._contains(role, principal, *extra_info)
                    if contains:
                        msg.append('{0} contains {1} and {2} AND'
                                   .format(role, principal, extra_info))
                    else:
                        msg.append('{0} DOES NOT contain {1} and {2}'
                                   .format(role, principal, extra_info))
                        break_it = True
            except (AttributeError, TypeError) as e:
                raise NotImplementedError(RoleSet.DEFINE_CONTAINS.format(e, role))
        self._traverse(self._roles, visitor)
        return '\n'.join(msg)

    def _contains(self, role, principal, *extra_info):
        contains = role.contains(principal, *extra_info)
        if not isinstance(contains, bool):
            raise TypeError("{}.'contains' does not return a boolean value".format(role))
        return contains

    def _traverse(self, roles, visitor):
        for role in roles:
            visitor(role)

    @property
    def roles(self):
        return self._roles


class AllowRoleSet(RoleSet):
    pass


class DenyRoleSet(RoleSet):
    pass