Skip to content

Commit ae0a7ee

Browse files
authored
Merge pull request #16 from python-scim/scim2-models-exceptions
Use scim2-models native exceptions
2 parents a3d4f92 + 15c4f4f commit ae0a7ee

File tree

9 files changed

+91
-88
lines changed

9 files changed

+91
-88
lines changed

scim2_server/backend.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,18 @@
1111
from scim2_models import Attribute
1212
from scim2_models import BaseModel
1313
from scim2_models import CaseExact
14-
from scim2_models import Error
1514
from scim2_models import Extension
1615
from scim2_models import Meta
1716
from scim2_models import Resource
1817
from scim2_models import ResourceType
1918
from scim2_models import Schema
2019
from scim2_models import SearchRequest
2120
from scim2_models import Uniqueness
21+
from scim2_models import UniquenessException
2222
from werkzeug.http import generate_etag
2323

2424
from scim2_server.filter import evaluate_filter
2525
from scim2_server.operators import ResolveSortOperator
26-
from scim2_server.utils import SCIMException
2726
from scim2_server.utils import get_by_alias
2827

2928

@@ -120,10 +119,9 @@ def query_resources(
120119
Resources. The List must contain a copy of resources.
121120
Mutating elements in the List must not modify the data
122121
stored in the backend.
123-
:raises SCIMException: If the backend only supports querying for
124-
one resource type at a time, setting resource_type_id to
125-
None the backend may raise a
126-
SCIMException(Error.make_too_many_error()).
122+
:raises TooManyException: If the backend only supports querying
123+
for one resource type at a time, setting resource_type_id to
124+
None the backend may raise TooManyException.
127125
"""
128126
raise NotImplementedError
129127

@@ -353,7 +351,7 @@ def create_resource(
353351
if existing_resource.meta.resource_type == resource_type_id:
354352
existing_value = unique_attribute.get_attribute(existing_resource)
355353
if existing_value == new_value:
356-
raise SCIMException(Error.make_uniqueness_error())
354+
raise UniquenessException()
357355

358356
self.resources.append(resource)
359357
return resource
@@ -392,7 +390,7 @@ def update_resource(
392390
existing_resource
393391
)
394392
if existing_value == new_value:
395-
raise SCIMException(Error.make_uniqueness_error())
393+
raise UniquenessException()
396394

397395
self.resources[found_res_idx] = updated_resource
398396
return updated_resource

scim2_server/filter.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
from scim2_filter_parser import ast as scim2ast
44
from scim2_models import BaseModel
55
from scim2_models import CaseExact
6-
from scim2_models import Error
6+
from scim2_models import InvalidFilterException
77

8-
from scim2_server.utils import SCIMException
98
from scim2_server.utils import get_by_alias
109
from scim2_server.utils import parse_new_value
1110

@@ -125,4 +124,4 @@ def check_comparable_value(value):
125124
status code 400) with "scimType" of "invalidFilter"."
126125
"""
127126
if isinstance(value, bytes | bool | NoneType):
128-
raise SCIMException(Error.make_invalid_filter_error())
127+
raise InvalidFilterException()

scim2_server/operators.py

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55
from scim2_filter_parser.parser import SCIMParser
66
from scim2_models import BaseModel
77
from scim2_models import CaseExact
8-
from scim2_models import Error
8+
from scim2_models import InvalidPathException
9+
from scim2_models import InvalidValueException
910
from scim2_models import Mutability
11+
from scim2_models import MutabilityException
12+
from scim2_models import NoTargetException
1013
from scim2_models import PatchOperation
1114
from scim2_models import Required
1215
from scim2_models import Resource
1316
from scim2_models import Returned
17+
from scim2_models import SensitiveException
1418

1519
from scim2_server.filter import evaluate_filter
16-
from scim2_server.utils import SCIMException
1720
from scim2_server.utils import get_by_alias
1821
from scim2_server.utils import get_or_create
1922
from scim2_server.utils import handle_extension
@@ -55,7 +58,7 @@ def parse_attribute_path(attribute_path: str | None) -> dict[str, Any] | None:
5558

5659
match = ATTRIBUTE_PATH_REGEX.match(attribute_path)
5760
if not match:
58-
raise SCIMException(Error.make_invalid_path_error())
61+
raise InvalidPathException()
5962
parse_attribute_path.cache[attribute_path] = match.groupdict()
6063
return match.groupdict()
6164

@@ -148,7 +151,7 @@ def match_multi_valued_attribute_sub(
148151
attribute_name = get_by_alias(type(model), attribute)
149152
multi_valued_attribute = get_or_create(model, attribute_name, True)
150153
if not isinstance(multi_valued_attribute, list):
151-
raise SCIMException(Error.make_invalid_path_error())
154+
raise InvalidPathException()
152155
token_stream = SCIMLexer().tokenize(condition)
153156
condition = SCIMParser().parse(token_stream)
154157
self.init_return(model, attribute_name, sub_attribute, self.value)
@@ -160,13 +163,13 @@ def match_multi_valued_attribute(
160163
self, attribute: str, condition: str, model: BaseModel
161164
):
162165
if self.REQUIRES_VALUE and not isinstance(self.value, dict):
163-
raise SCIMException(Error.make_invalid_value_error())
166+
raise InvalidValueException()
164167
attribute_name = get_by_alias(type(model), attribute)
165168
multi_valued_attribute = get_or_create(
166169
model, attribute_name, self.REQUIRES_VALUE
167170
)
168171
if not isinstance(multi_valued_attribute, list):
169-
raise SCIMException(Error.make_invalid_path_error())
172+
raise InvalidPathException()
170173
token_stream = SCIMLexer().tokenize(condition)
171174
condition = SCIMParser().parse(token_stream)
172175
if self.REQUIRES_VALUE:
@@ -196,7 +199,7 @@ def match_complex_attribute(self, attribute: str, model: BaseModel, sub_path: st
196199
self.match_attribute(sub_path, value)
197200
else:
198201
if not isinstance(complex_attribute, BaseModel):
199-
raise SCIMException(Error.make_invalid_path_error())
202+
raise InvalidPathException()
200203
self.match_attribute(sub_path, complex_attribute)
201204

202205
def match_attribute(self, attribute: str, model: BaseModel):
@@ -205,9 +208,9 @@ def match_attribute(self, attribute: str, model: BaseModel):
205208

206209
def call_on_root(self, model: Resource):
207210
if not self.OPERATE_ON_ROOT:
208-
raise SCIMException(Error.make_no_target_error())
211+
raise NoTargetException()
209212
if not isinstance(self.value, dict):
210-
raise SCIMException(Error.make_invalid_value_error())
213+
raise InvalidValueException()
211214
for k, v in self.value.items():
212215
ext, scim_name = handle_extension(model, k)
213216
if ext == model:
@@ -233,7 +236,7 @@ def operation(cls, model: BaseModel, attribute: str, value: Any):
233236
return
234237

235238
if model.get_field_annotation(alias, Mutability) == Mutability.read_only:
236-
raise SCIMException(Error.make_mutability_error())
239+
raise MutabilityException()
237240

238241
if model.get_field_multiplicity(alias):
239242
if getattr(model, alias) is None:
@@ -247,7 +250,7 @@ def operation(cls, model: BaseModel, attribute: str, value: Any):
247250
model.get_field_annotation(alias, Required) == Required.true
248251
and not new_value
249252
):
250-
raise SCIMException(Error.make_invalid_value_error())
253+
raise InvalidValueException()
251254
setattr(model, alias, new_value)
252255

253256

@@ -268,10 +271,10 @@ def operation(cls, model: BaseModel, attribute: str, value: Any):
268271
Mutability.read_only,
269272
Mutability.immutable,
270273
):
271-
raise SCIMException(Error.make_mutability_error())
274+
raise MutabilityException()
272275

273276
if model.get_field_annotation(alias, Required) == Required.true:
274-
raise SCIMException(Error.make_invalid_value_error())
277+
raise InvalidValueException()
275278

276279
setattr(model, alias, None)
277280

@@ -283,21 +286,21 @@ class ReplaceOperator(Operator):
283286
def operation(cls, model: BaseModel, attribute: str, value: Any):
284287
alias = get_by_alias(type(model), attribute)
285288
if model.get_field_multiplicity(alias) and not isinstance(value, list):
286-
raise SCIMException(Error.make_invalid_value_error())
289+
raise InvalidValueException()
287290

288291
existing_value = getattr(model, alias)
289292
new_value = parse_new_value(model, alias, value)
290293
if new_value == existing_value:
291294
return
292295

293296
if model.get_field_annotation(alias, Mutability) == Mutability.read_only:
294-
raise SCIMException(Error.make_mutability_error())
297+
raise MutabilityException()
295298

296299
if (
297300
model.get_field_annotation(alias, Required) == Required.true
298301
and not new_value
299302
):
300-
raise SCIMException(Error.make_invalid_value_error())
303+
raise InvalidValueException()
301304
setattr(model, alias, new_value)
302305

303306

@@ -372,7 +375,7 @@ def init_return(
372375
model.get_field_annotation(alias, Mutability) == Mutability.write_only
373376
or model.get_field_annotation(alias, Returned) == Returned.never
374377
):
375-
raise SCIMException(Error.make_sensitive_error())
378+
raise SensitiveException()
376379

377380
@classmethod
378381
def operation(

scim2_server/provider.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from scim2_models import Resource
2121
from scim2_models import ResourceType
2222
from scim2_models import Schema
23+
from scim2_models import SCIMException
2324
from scim2_models import SearchRequest
2425
from scim2_models import ServiceProviderConfig
2526
from scim2_models import Sort
@@ -39,7 +40,6 @@
3940

4041
from scim2_server.backend import Backend
4142
from scim2_server.operators import patch_resource
42-
from scim2_server.utils import SCIMException
4343
from scim2_server.utils import merge_resources
4444

4545

@@ -537,7 +537,7 @@ def wsgi_app(self, request: Request, environ):
537537
return self.make_error(Error(status=e.code, detail=e.description))
538538
except SCIMException as e:
539539
self.log.exception(e)
540-
return self.make_error(e.scim_error)
540+
return self.make_error(e.to_error())
541541
except ValidationError as e:
542542
self.log.exception(e)
543543
return self.make_error(Error(status=400, detail=str(e)))

scim2_server/utils.py

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,16 @@
88
from pydantic import EmailStr
99
from pydantic import ValidationError
1010
from scim2_models import BaseModel
11-
from scim2_models import Error
1211
from scim2_models import Extension
12+
from scim2_models import InvalidValueException
1313
from scim2_models import Mutability
14+
from scim2_models import MutabilityException
15+
from scim2_models import NoTargetException
1416
from scim2_models import Resource
1517
from scim2_models import ResourceType
1618
from scim2_models import Schema
1719

1820

19-
class SCIMException(Exception):
20-
"""A wrapper class, because an "Error" does not inherit from Exception and should not be raised."""
21-
22-
def __init__(self, scim_error: Error):
23-
self.scim_error = scim_error
24-
25-
2621
def load_json_resource(json_name: str) -> list:
2722
"""Load a JSON document from the scim2_server package resources."""
2823
fp = importlib.resources.files("scim2_server") / "resources" / json_name
@@ -69,7 +64,7 @@ def merge_resources(target: Resource, updates: BaseModel):
6964
if mutability == Mutability.immutable and getattr(
7065
target, set_attribute
7166
) not in (None, new_value):
72-
raise SCIMException(Error.make_mutability_error())
67+
raise MutabilityException()
7368
setattr(target, set_attribute, new_value)
7469

7570

@@ -82,8 +77,8 @@ def get_by_alias(
8277
:param scim_name: SCIM attribute name
8378
:param allow_none: Allow returning None if attribute is not found
8479
:return: pydantic attribute name
85-
:raises SCIMException: If no attribute is found and allow_none is
86-
False
80+
:raises NoTargetException: If no attribute is found and allow_none
81+
is False
8782
"""
8883
try:
8984
return next(
@@ -94,7 +89,7 @@ def get_by_alias(
9489
except StopIteration as e:
9590
if allow_none:
9691
return None
97-
raise SCIMException(Error.make_no_target_error()) from e
92+
raise NoTargetException() from e
9893

9994

10095
def get_or_create(
@@ -107,15 +102,15 @@ def get_or_create(
107102
:param check_mutability: If True, validate that the attribute is
108103
mutable
109104
:return: A complex attribute model
110-
:raises SCIMException: If attribute is not mutable and
105+
:raises MutabilityException: If attribute is not mutable and
111106
check_mutability is True
112107
"""
113108
if check_mutability:
114109
if model.get_field_annotation(attribute_name, Mutability) in (
115110
Mutability.read_only,
116111
Mutability.immutable,
117112
):
118-
raise SCIMException(Error.make_mutability_error())
113+
raise MutabilityException()
119114
ret = getattr(model, attribute_name, None)
120115
if not ret:
121116
if model.get_field_multiplicity(attribute_name):
@@ -164,8 +159,8 @@ def model_validate_from_dict(field_root_type: type[BaseModel], value: dict) -> A
164159
def parse_new_value(model: BaseModel, attribute_name: str, value: Any) -> Any:
165160
"""Given a model and attribute name, attempt to parse a new value so that the type matches the type expected by the model.
166161
167-
:raises SCIMException: If attribute can not be mapped to the
168-
required type
162+
:raises InvalidValueException: If attribute can not be mapped to
163+
the required type
169164
"""
170165
field_root_type = model.get_field_root_type(attribute_name)
171166
try:
@@ -195,5 +190,5 @@ def parse_new_value(model: BaseModel, attribute_name: str, value: Any) -> Any:
195190
else:
196191
new_value = field_root_type(value)
197192
except (AttributeError, TypeError, ValueError, ValidationError) as e:
198-
raise SCIMException(Error.make_invalid_value_error()) from e
193+
raise InvalidValueException() from e
199194
return new_value

0 commit comments

Comments
 (0)