Skip to content

Client

respo.client

RespoClient

Entity that can be given a role.

Implements methods for adding and removing roles and method has_permission() for checking them using respo.RespoModel instance.

Parameters:

Name Type Description Default
roles str

string with roles separated by comma

''

Examples:

>>> RespoClient(None).roles
[]
>>> RespoClient("abc,def").roles
["abc", "def"]
>>> str(RespoClient("abc,def"))
"abc,def"
Source code in respo/client.py
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
class RespoClient:
    """Entity that can be given a role.

    Implements methods for adding and removing roles and method
    has_permission() for checking them using respo.RespoModel instance.

    Args:
        roles: string with roles separated by comma

    Examples:
        >>> RespoClient(None).roles
        []
        >>> RespoClient("abc,def").roles
        ["abc", "def"]
        >>> str(RespoClient("abc,def"))
        "abc,def"
    """

    def __init__(self, roles: str = "") -> None:
        if not roles:
            self.roles: List[str] = []
        else:
            self.roles: List[str] = roles.split(",")

    def __str__(self) -> str:
        return ",".join(self.roles)

    @staticmethod
    def validate_role(role_name: str, respo_model: core.RespoModel) -> core.RoleLabel:
        """Validates role name.

        Raises:
            ValueError: role_name is instance of str and doesn't match single
            label regex.
            RespoClientError: role_name does not exist in model.
        """
        role_label = core.RoleLabel(role_name=role_name)
        if role_label.role_label not in respo_model.ROLES:
            raise exceptions.RespoClientError(
                f"Role not found in respo model: {role_name}."
            )
        return role_label

    def add_role(
        self,
        role_name: str,
        respo_model: Optional[core.RespoModel] = None,
        validate_input: bool = settings.config.RESPO_CHECK_FORCE,
    ) -> bool:
        """Adds role to this client after optional validation.

        If validate_input is False, there will be no safe checks. It defaults to
        respo.config.RESPO_CHECK_FORCE and can be changed directly or using
        environment variable RESPO_CHECK_FORCE.

        Return:
            True: role was added.
            False: role already exists in the client.

        Raises:
            ValueError: role_name is instance of str and doesn't single
            label regex.
            TypeError: respo_model is None when at the same time when
            validate_input is True.
            RespoClientError: role_name does not exist in the
            model (only with validation).

        Examples:
            >>> respo_client.add_role("sample_role", validate_input=False)
            True
            >>> respo_client.add_role(
                    respo_model.ROLES.SAMPLE_ROLE,
                    respo_model,
                    validate_input=True,
                )
            False
        """
        if validate_input and respo_model is not None:
            role_label = self.validate_role(
                role_name=role_name, respo_model=respo_model
            )
        elif validate_input and respo_model is None:
            raise TypeError("respo_model cannot be None when validate_input is True")
        else:
            role_label = core.RoleLabel(role_name=role_name)

        if role_label.role_label in self.roles:
            return False
        else:
            self.roles.append(role_label.role_label)
            return True

    def remove_role(
        self,
        role_name: str,
        respo_model: Optional[core.RespoModel] = None,
        validate_input: bool = settings.config.RESPO_CHECK_FORCE,
    ) -> bool:
        """Removes role from this client after optional validation.

        If validate_input is False, there will be no safe checks. It defaults to
        respo.config.RESPO_CHECK_FORCE and can be changed directly or using
        environment variable RESPO_CHECK_FORCE.

        Return:
            True: role was removed.
            False: role does not exists in the client.

        Raises:
            ValueError: role_name is instance of str and doesn't single
            label regex.
            TypeError: respo_model is None when at the same time
            validate_input is True.
            RespoClientError: role_name does not exist in the
            model (only with validation).

        Examples:
            >>> respo_client.remove_role("sample_role", validate_input=False)
            True
            >>> respo_client.remove_role(
                    respo_model.ROLES.SAMPLE_ROLE,
                    respo_model,
                    validate_input=True,
                )
            False
        """
        if validate_input and respo_model is not None:
            role_label = self.validate_role(
                role_name=role_name, respo_model=respo_model
            )
        elif validate_input and respo_model is None:
            raise TypeError("respo_model cannot be None when validate_input is True")
        else:
            role_label = core.RoleLabel(role_name=role_name)

        if role_label.role_label in self.roles:
            self.roles.remove(role_label.role_label)
            return True
        else:
            return False

    def has_permission(
        self, permission_name: str, respo_model: core.RespoModel
    ) -> bool:
        """Checks if *this* client does have specific permission.

        Under the hood searches through prepared role-permissions dict to
        speed this up (after resolving the complex nested rules logic etc).
        For very large self.roles this can be pretty slow anyway.

        Return:
            True: client has permission.
            False: client doesn't have permission.

        Raises:
            ValueError: permission_name doesn't match double label regex.

        Examples:
            >>> respo_client.has_permission("users.read", respo_model)
            True
            >>> respo_client.has_permission(
                    respo_model.PERMS.USERS__READ_ALL, respo_model
                )
            True
        """
        permission_label = core.PermissionLabel(permission_name)
        for role in self.roles:
            if permission_label.permission_name in respo_model.ROLES.permissions(role):
                return True
        return False

add_role(role_name, respo_model=None, validate_input=settings.config.RESPO_CHECK_FORCE)

Adds role to this client after optional validation.

If validate_input is False, there will be no safe checks. It defaults to respo.config.RESPO_CHECK_FORCE and can be changed directly or using environment variable RESPO_CHECK_FORCE.

Return

True: role was added. False: role already exists in the client.

Raises:

Type Description
ValueError

role_name is instance of str and doesn't single

TypeError

respo_model is None when at the same time when

RespoClientError

role_name does not exist in the

Examples:

>>> respo_client.add_role("sample_role", validate_input=False)
True
>>> respo_client.add_role(
        respo_model.ROLES.SAMPLE_ROLE,
        respo_model,
        validate_input=True,
    )
False
Source code in respo/client.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
def add_role(
    self,
    role_name: str,
    respo_model: Optional[core.RespoModel] = None,
    validate_input: bool = settings.config.RESPO_CHECK_FORCE,
) -> bool:
    """Adds role to this client after optional validation.

    If validate_input is False, there will be no safe checks. It defaults to
    respo.config.RESPO_CHECK_FORCE and can be changed directly or using
    environment variable RESPO_CHECK_FORCE.

    Return:
        True: role was added.
        False: role already exists in the client.

    Raises:
        ValueError: role_name is instance of str and doesn't single
        label regex.
        TypeError: respo_model is None when at the same time when
        validate_input is True.
        RespoClientError: role_name does not exist in the
        model (only with validation).

    Examples:
        >>> respo_client.add_role("sample_role", validate_input=False)
        True
        >>> respo_client.add_role(
                respo_model.ROLES.SAMPLE_ROLE,
                respo_model,
                validate_input=True,
            )
        False
    """
    if validate_input and respo_model is not None:
        role_label = self.validate_role(
            role_name=role_name, respo_model=respo_model
        )
    elif validate_input and respo_model is None:
        raise TypeError("respo_model cannot be None when validate_input is True")
    else:
        role_label = core.RoleLabel(role_name=role_name)

    if role_label.role_label in self.roles:
        return False
    else:
        self.roles.append(role_label.role_label)
        return True

has_permission(permission_name, respo_model)

Checks if this client does have specific permission.

Under the hood searches through prepared role-permissions dict to speed this up (after resolving the complex nested rules logic etc). For very large self.roles this can be pretty slow anyway.

Return

True: client has permission. False: client doesn't have permission.

Raises:

Type Description
ValueError

permission_name doesn't match double label regex.

Examples:

>>> respo_client.has_permission("users.read", respo_model)
True
>>> respo_client.has_permission(
        respo_model.PERMS.USERS__READ_ALL, respo_model
    )
True
Source code in respo/client.py
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
def has_permission(
    self, permission_name: str, respo_model: core.RespoModel
) -> bool:
    """Checks if *this* client does have specific permission.

    Under the hood searches through prepared role-permissions dict to
    speed this up (after resolving the complex nested rules logic etc).
    For very large self.roles this can be pretty slow anyway.

    Return:
        True: client has permission.
        False: client doesn't have permission.

    Raises:
        ValueError: permission_name doesn't match double label regex.

    Examples:
        >>> respo_client.has_permission("users.read", respo_model)
        True
        >>> respo_client.has_permission(
                respo_model.PERMS.USERS__READ_ALL, respo_model
            )
        True
    """
    permission_label = core.PermissionLabel(permission_name)
    for role in self.roles:
        if permission_label.permission_name in respo_model.ROLES.permissions(role):
            return True
    return False

remove_role(role_name, respo_model=None, validate_input=settings.config.RESPO_CHECK_FORCE)

Removes role from this client after optional validation.

If validate_input is False, there will be no safe checks. It defaults to respo.config.RESPO_CHECK_FORCE and can be changed directly or using environment variable RESPO_CHECK_FORCE.

Return

True: role was removed. False: role does not exists in the client.

Raises:

Type Description
ValueError

role_name is instance of str and doesn't single

TypeError

respo_model is None when at the same time

RespoClientError

role_name does not exist in the

Examples:

>>> respo_client.remove_role("sample_role", validate_input=False)
True
>>> respo_client.remove_role(
        respo_model.ROLES.SAMPLE_ROLE,
        respo_model,
        validate_input=True,
    )
False
Source code in respo/client.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
def remove_role(
    self,
    role_name: str,
    respo_model: Optional[core.RespoModel] = None,
    validate_input: bool = settings.config.RESPO_CHECK_FORCE,
) -> bool:
    """Removes role from this client after optional validation.

    If validate_input is False, there will be no safe checks. It defaults to
    respo.config.RESPO_CHECK_FORCE and can be changed directly or using
    environment variable RESPO_CHECK_FORCE.

    Return:
        True: role was removed.
        False: role does not exists in the client.

    Raises:
        ValueError: role_name is instance of str and doesn't single
        label regex.
        TypeError: respo_model is None when at the same time
        validate_input is True.
        RespoClientError: role_name does not exist in the
        model (only with validation).

    Examples:
        >>> respo_client.remove_role("sample_role", validate_input=False)
        True
        >>> respo_client.remove_role(
                respo_model.ROLES.SAMPLE_ROLE,
                respo_model,
                validate_input=True,
            )
        False
    """
    if validate_input and respo_model is not None:
        role_label = self.validate_role(
            role_name=role_name, respo_model=respo_model
        )
    elif validate_input and respo_model is None:
        raise TypeError("respo_model cannot be None when validate_input is True")
    else:
        role_label = core.RoleLabel(role_name=role_name)

    if role_label.role_label in self.roles:
        self.roles.remove(role_label.role_label)
        return True
    else:
        return False

validate_role(role_name, respo_model) staticmethod

Validates role name.

Raises:

Type Description
ValueError

role_name is instance of str and doesn't match single

RespoClientError

role_name does not exist in model.

Source code in respo/client.py
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@staticmethod
def validate_role(role_name: str, respo_model: core.RespoModel) -> core.RoleLabel:
    """Validates role name.

    Raises:
        ValueError: role_name is instance of str and doesn't match single
        label regex.
        RespoClientError: role_name does not exist in model.
    """
    role_label = core.RoleLabel(role_name=role_name)
    if role_label.role_label not in respo_model.ROLES:
        raise exceptions.RespoClientError(
            f"Role not found in respo model: {role_name}."
        )
    return role_label