scim2-models 0.5.2__py3-none-any.whl → 0.6.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scim2_models/__init__.py +32 -0
- scim2_models/attributes.py +5 -1
- scim2_models/base.py +52 -8
- scim2_models/exceptions.py +265 -0
- scim2_models/messages/bulk.py +3 -7
- scim2_models/messages/error.py +184 -15
- scim2_models/messages/list_response.py +2 -5
- scim2_models/messages/message.py +4 -4
- scim2_models/messages/patch_op.py +127 -261
- scim2_models/messages/search_request.py +9 -57
- scim2_models/path.py +733 -0
- scim2_models/reference.py +139 -48
- scim2_models/resources/enterprise_user.py +10 -8
- scim2_models/resources/group.py +9 -7
- scim2_models/resources/resource.py +116 -29
- scim2_models/resources/resource_type.py +15 -14
- scim2_models/resources/schema.py +15 -20
- scim2_models/resources/service_provider_config.py +10 -13
- scim2_models/resources/user.py +13 -10
- scim2_models/scim_object.py +84 -1
- scim2_models/utils.py +0 -140
- {scim2_models-0.5.2.dist-info → scim2_models-0.6.1.dist-info}/METADATA +2 -2
- scim2_models-0.6.1.dist-info/RECORD +30 -0
- scim2_models/urn.py +0 -126
- scim2_models-0.5.2.dist-info/RECORD +0 -29
- {scim2_models-0.5.2.dist-info → scim2_models-0.6.1.dist-info}/WHEEL +0 -0
scim2_models/messages/error.py
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
from collections.abc import Mapping
|
|
3
|
+
from collections.abc import Sequence
|
|
1
4
|
from typing import Annotated
|
|
5
|
+
from typing import Any
|
|
2
6
|
|
|
3
7
|
from pydantic import PlainSerializer
|
|
8
|
+
from pydantic import ValidationError
|
|
4
9
|
|
|
5
|
-
from ..
|
|
10
|
+
from ..path import URN
|
|
6
11
|
from ..utils import _int_to_str
|
|
7
12
|
from .message import Message
|
|
8
13
|
|
|
9
14
|
|
|
10
15
|
class Error(Message):
|
|
11
|
-
"""Representation of SCIM API errors.
|
|
16
|
+
"""Representation of SCIM API errors.
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
:rfc:`RFC 7644 Section 3.12 <7644#section-3.12>`
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
__schema__ = URN("urn:ietf:params:scim:api:messages:2.0:Error")
|
|
16
22
|
|
|
17
23
|
status: Annotated[int | None, PlainSerializer(_int_to_str)] = None
|
|
18
24
|
"""The HTTP status code (see Section 6 of [RFC7231]) expressed as a JSON
|
|
@@ -26,7 +32,18 @@ class Error(Message):
|
|
|
26
32
|
|
|
27
33
|
@classmethod
|
|
28
34
|
def make_invalid_filter_error(cls) -> "Error":
|
|
29
|
-
"""Pre-defined error intended to be raised when the specified filter syntax was invalid (does not comply with :rfc:`Figure 1 of RFC7644 <7644#section-3.4.2.2>`), or the specified attribute and filter comparison combination is not supported.
|
|
35
|
+
"""Pre-defined error intended to be raised when the specified filter syntax was invalid (does not comply with :rfc:`Figure 1 of RFC7644 <7644#section-3.4.2.2>`), or the specified attribute and filter comparison combination is not supported.
|
|
36
|
+
|
|
37
|
+
.. deprecated:: 0.6.0
|
|
38
|
+
Use :class:`~scim2_models.InvalidFilterException` instead.
|
|
39
|
+
Will be removed in 0.7.0.
|
|
40
|
+
"""
|
|
41
|
+
warnings.warn(
|
|
42
|
+
"make_invalid_filter_error is deprecated, use InvalidFilterException().to_error() instead. "
|
|
43
|
+
"Will be removed in 0.7.0.",
|
|
44
|
+
DeprecationWarning,
|
|
45
|
+
stacklevel=2,
|
|
46
|
+
)
|
|
30
47
|
return Error(
|
|
31
48
|
status=400,
|
|
32
49
|
scim_type="invalidFilter",
|
|
@@ -35,7 +52,18 @@ class Error(Message):
|
|
|
35
52
|
|
|
36
53
|
@classmethod
|
|
37
54
|
def make_too_many_error(cls) -> "Error":
|
|
38
|
-
"""Pre-defined error intended to be raised when the specified filter yields many more results than the server is willing to calculate or process. For example, a filter such as ``(userName pr)`` by itself would return all entries with a ``userName`` and MAY not be acceptable to the service provider.
|
|
55
|
+
"""Pre-defined error intended to be raised when the specified filter yields many more results than the server is willing to calculate or process. For example, a filter such as ``(userName pr)`` by itself would return all entries with a ``userName`` and MAY not be acceptable to the service provider.
|
|
56
|
+
|
|
57
|
+
.. deprecated:: 0.6.0
|
|
58
|
+
Use :class:`~scim2_models.TooManyException` instead.
|
|
59
|
+
Will be removed in 0.7.0.
|
|
60
|
+
"""
|
|
61
|
+
warnings.warn(
|
|
62
|
+
"make_too_many_error is deprecated, use TooManyException().to_error() instead. "
|
|
63
|
+
"Will be removed in 0.7.0.",
|
|
64
|
+
DeprecationWarning,
|
|
65
|
+
stacklevel=2,
|
|
66
|
+
)
|
|
39
67
|
return Error(
|
|
40
68
|
status=400,
|
|
41
69
|
scim_type="tooMany",
|
|
@@ -44,7 +72,18 @@ class Error(Message):
|
|
|
44
72
|
|
|
45
73
|
@classmethod
|
|
46
74
|
def make_uniqueness_error(cls) -> "Error":
|
|
47
|
-
"""Pre-defined error intended to be raised when One or more of the attribute values are already in use or are reserved.
|
|
75
|
+
"""Pre-defined error intended to be raised when One or more of the attribute values are already in use or are reserved.
|
|
76
|
+
|
|
77
|
+
.. deprecated:: 0.6.0
|
|
78
|
+
Use :class:`~scim2_models.UniquenessException` instead.
|
|
79
|
+
Will be removed in 0.7.0.
|
|
80
|
+
"""
|
|
81
|
+
warnings.warn(
|
|
82
|
+
"make_uniqueness_error is deprecated, use UniquenessException().to_error() instead. "
|
|
83
|
+
"Will be removed in 0.7.0.",
|
|
84
|
+
DeprecationWarning,
|
|
85
|
+
stacklevel=2,
|
|
86
|
+
)
|
|
48
87
|
return Error(
|
|
49
88
|
status=409,
|
|
50
89
|
scim_type="uniqueness",
|
|
@@ -53,7 +92,18 @@ class Error(Message):
|
|
|
53
92
|
|
|
54
93
|
@classmethod
|
|
55
94
|
def make_mutability_error(cls) -> "Error":
|
|
56
|
-
"""Pre-defined error intended to be raised when the attempted modification is not compatible with the target attribute's mutability or current state (e.g., modification of an "immutable" attribute with an existing value).
|
|
95
|
+
"""Pre-defined error intended to be raised when the attempted modification is not compatible with the target attribute's mutability or current state (e.g., modification of an "immutable" attribute with an existing value).
|
|
96
|
+
|
|
97
|
+
.. deprecated:: 0.6.0
|
|
98
|
+
Use :class:`~scim2_models.MutabilityException` instead.
|
|
99
|
+
Will be removed in 0.7.0.
|
|
100
|
+
"""
|
|
101
|
+
warnings.warn(
|
|
102
|
+
"make_mutability_error is deprecated, use MutabilityException().to_error() instead. "
|
|
103
|
+
"Will be removed in 0.7.0.",
|
|
104
|
+
DeprecationWarning,
|
|
105
|
+
stacklevel=2,
|
|
106
|
+
)
|
|
57
107
|
return Error(
|
|
58
108
|
status=400,
|
|
59
109
|
scim_type="mutability",
|
|
@@ -62,7 +112,18 @@ class Error(Message):
|
|
|
62
112
|
|
|
63
113
|
@classmethod
|
|
64
114
|
def make_invalid_syntax_error(cls) -> "Error":
|
|
65
|
-
"""Pre-defined error intended to be raised when the request body message structure was invalid or did not conform to the request schema.
|
|
115
|
+
"""Pre-defined error intended to be raised when the request body message structure was invalid or did not conform to the request schema.
|
|
116
|
+
|
|
117
|
+
.. deprecated:: 0.6.0
|
|
118
|
+
Use :class:`~scim2_models.InvalidSyntaxException` instead.
|
|
119
|
+
Will be removed in 0.7.0.
|
|
120
|
+
"""
|
|
121
|
+
warnings.warn(
|
|
122
|
+
"make_invalid_syntax_error is deprecated, use InvalidSyntaxException().to_error() instead. "
|
|
123
|
+
"Will be removed in 0.7.0.",
|
|
124
|
+
DeprecationWarning,
|
|
125
|
+
stacklevel=2,
|
|
126
|
+
)
|
|
66
127
|
return Error(
|
|
67
128
|
status=400,
|
|
68
129
|
scim_type="invalidSyntax",
|
|
@@ -71,7 +132,18 @@ class Error(Message):
|
|
|
71
132
|
|
|
72
133
|
@classmethod
|
|
73
134
|
def make_invalid_path_error(cls) -> "Error":
|
|
74
|
-
"""Pre-defined error intended to be raised when the "path" attribute was invalid or malformed (see :rfc:`Figure 7 of RFC7644 <7644#section-3.5.2>`).
|
|
135
|
+
"""Pre-defined error intended to be raised when the "path" attribute was invalid or malformed (see :rfc:`Figure 7 of RFC7644 <7644#section-3.5.2>`).
|
|
136
|
+
|
|
137
|
+
.. deprecated:: 0.6.0
|
|
138
|
+
Use :class:`~scim2_models.InvalidPathException` instead.
|
|
139
|
+
Will be removed in 0.7.0.
|
|
140
|
+
"""
|
|
141
|
+
warnings.warn(
|
|
142
|
+
"make_invalid_path_error is deprecated, use InvalidPathException().to_error() instead. "
|
|
143
|
+
"Will be removed in 0.7.0.",
|
|
144
|
+
DeprecationWarning,
|
|
145
|
+
stacklevel=2,
|
|
146
|
+
)
|
|
75
147
|
return Error(
|
|
76
148
|
status=400,
|
|
77
149
|
scim_type="invalidPath",
|
|
@@ -80,7 +152,18 @@ class Error(Message):
|
|
|
80
152
|
|
|
81
153
|
@classmethod
|
|
82
154
|
def make_no_target_error(cls) -> "Error":
|
|
83
|
-
"""Pre-defined error intended to be raised when the specified "path" did not yield an attribute or attribute value that could be operated on. This occurs when the specified "path" value contains a filter that yields no match.
|
|
155
|
+
"""Pre-defined error intended to be raised when the specified "path" did not yield an attribute or attribute value that could be operated on. This occurs when the specified "path" value contains a filter that yields no match.
|
|
156
|
+
|
|
157
|
+
.. deprecated:: 0.6.0
|
|
158
|
+
Use :class:`~scim2_models.NoTargetException` instead.
|
|
159
|
+
Will be removed in 0.7.0.
|
|
160
|
+
"""
|
|
161
|
+
warnings.warn(
|
|
162
|
+
"make_no_target_error is deprecated, use NoTargetException().to_error() instead. "
|
|
163
|
+
"Will be removed in 0.7.0.",
|
|
164
|
+
DeprecationWarning,
|
|
165
|
+
stacklevel=2,
|
|
166
|
+
)
|
|
84
167
|
return Error(
|
|
85
168
|
status=400,
|
|
86
169
|
scim_type="noTarget",
|
|
@@ -89,7 +172,18 @@ class Error(Message):
|
|
|
89
172
|
|
|
90
173
|
@classmethod
|
|
91
174
|
def make_invalid_value_error(cls) -> "Error":
|
|
92
|
-
"""Pre-defined error intended to be raised when a required value was missing, or the value specified was not compatible with the operation or attribute type (see :rfc:`Section 2.2 of RFC7643 <7643#section-2.2>`), or resource schema (see :rfc:`Section 4 of RFC7643 <7643#section-4>`).
|
|
175
|
+
"""Pre-defined error intended to be raised when a required value was missing, or the value specified was not compatible with the operation or attribute type (see :rfc:`Section 2.2 of RFC7643 <7643#section-2.2>`), or resource schema (see :rfc:`Section 4 of RFC7643 <7643#section-4>`).
|
|
176
|
+
|
|
177
|
+
.. deprecated:: 0.6.0
|
|
178
|
+
Use :class:`~scim2_models.InvalidValueException` instead.
|
|
179
|
+
Will be removed in 0.7.0.
|
|
180
|
+
"""
|
|
181
|
+
warnings.warn(
|
|
182
|
+
"make_invalid_value_error is deprecated, use InvalidValueException().to_error() instead. "
|
|
183
|
+
"Will be removed in 0.7.0.",
|
|
184
|
+
DeprecationWarning,
|
|
185
|
+
stacklevel=2,
|
|
186
|
+
)
|
|
93
187
|
return Error(
|
|
94
188
|
status=400,
|
|
95
189
|
scim_type="invalidValue",
|
|
@@ -98,7 +192,18 @@ class Error(Message):
|
|
|
98
192
|
|
|
99
193
|
@classmethod
|
|
100
194
|
def make_invalid_version_error(cls) -> "Error":
|
|
101
|
-
"""Pre-defined error intended to be raised when the specified SCIM protocol version is not supported (see :rfc:`Section 3.13 of RFC7644 <7644#section-3.13>`).
|
|
195
|
+
"""Pre-defined error intended to be raised when the specified SCIM protocol version is not supported (see :rfc:`Section 3.13 of RFC7644 <7644#section-3.13>`).
|
|
196
|
+
|
|
197
|
+
.. deprecated:: 0.6.0
|
|
198
|
+
Use :class:`~scim2_models.InvalidVersionException` instead.
|
|
199
|
+
Will be removed in 0.7.0.
|
|
200
|
+
"""
|
|
201
|
+
warnings.warn(
|
|
202
|
+
"make_invalid_version_error is deprecated, use InvalidVersionException().to_error() instead. "
|
|
203
|
+
"Will be removed in 0.7.0.",
|
|
204
|
+
DeprecationWarning,
|
|
205
|
+
stacklevel=2,
|
|
206
|
+
)
|
|
102
207
|
return Error(
|
|
103
208
|
status=400,
|
|
104
209
|
scim_type="invalidVers",
|
|
@@ -107,9 +212,73 @@ class Error(Message):
|
|
|
107
212
|
|
|
108
213
|
@classmethod
|
|
109
214
|
def make_sensitive_error(cls) -> "Error":
|
|
110
|
-
"""Pre-defined error intended to be raised when the specified request cannot be completed, due to the passing of sensitive (e.g., personal) information in a request URI. For example, personal information SHALL NOT be transmitted over request URIs. See :rfc:`Section 7.5.2 of RFC7644 <7644#section-7.5.2>`.
|
|
215
|
+
"""Pre-defined error intended to be raised when the specified request cannot be completed, due to the passing of sensitive (e.g., personal) information in a request URI. For example, personal information SHALL NOT be transmitted over request URIs. See :rfc:`Section 7.5.2 of RFC7644 <7644#section-7.5.2>`.
|
|
216
|
+
|
|
217
|
+
.. deprecated:: 0.6.0
|
|
218
|
+
Use :class:`~scim2_models.SensitiveException` instead.
|
|
219
|
+
Will be removed in 0.7.0.
|
|
220
|
+
"""
|
|
221
|
+
warnings.warn(
|
|
222
|
+
"make_sensitive_error is deprecated, use SensitiveException().to_error() instead. "
|
|
223
|
+
"Will be removed in 0.7.0.",
|
|
224
|
+
DeprecationWarning,
|
|
225
|
+
stacklevel=2,
|
|
226
|
+
)
|
|
111
227
|
return Error(
|
|
112
228
|
status=400,
|
|
113
229
|
scim_type="sensitive",
|
|
114
230
|
detail="""The specified request cannot be completed, due to the passing of sensitive (e.g., personal) information in a request URI. For example, personal information SHALL NOT be transmitted over request URIs. See Section 7.5.2. of RFC7644""",
|
|
115
231
|
)
|
|
232
|
+
|
|
233
|
+
@classmethod
|
|
234
|
+
def from_validation_error(cls, error: Mapping[str, Any]) -> "Error":
|
|
235
|
+
"""Convert a single Pydantic error dict to a SCIM Error.
|
|
236
|
+
|
|
237
|
+
If the error is a SCIM-specific error (raised via
|
|
238
|
+
:meth:`SCIMException.as_pydantic_error`), its scim_type and status
|
|
239
|
+
are preserved. Otherwise, a best-effort mapping is performed.
|
|
240
|
+
|
|
241
|
+
:param error: A single error dict from ``ValidationError.errors()``.
|
|
242
|
+
:return: A SCIM Error object.
|
|
243
|
+
"""
|
|
244
|
+
if error["type"].startswith("scim_"):
|
|
245
|
+
ctx = error.get("ctx", {})
|
|
246
|
+
return cls(
|
|
247
|
+
status=ctx.get("status", 400),
|
|
248
|
+
scim_type=ctx.get("scim_type"),
|
|
249
|
+
detail=error["msg"],
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
loc = ", ".join(str(loc) for loc in error["loc"])
|
|
253
|
+
detail = f"{error['msg']}: {loc}" if loc else error["msg"]
|
|
254
|
+
|
|
255
|
+
scim_type: str | None = None
|
|
256
|
+
error_type = error["type"]
|
|
257
|
+
if error_type in ("missing", "required_error"):
|
|
258
|
+
scim_type = "invalidValue"
|
|
259
|
+
elif error_type in (
|
|
260
|
+
"string_type",
|
|
261
|
+
"int_type",
|
|
262
|
+
"int_parsing",
|
|
263
|
+
"bool_type",
|
|
264
|
+
"bool_parsing",
|
|
265
|
+
"float_type",
|
|
266
|
+
"float_parsing",
|
|
267
|
+
"json_invalid",
|
|
268
|
+
"value_error",
|
|
269
|
+
):
|
|
270
|
+
scim_type = "invalidSyntax"
|
|
271
|
+
|
|
272
|
+
return cls(status=400, scim_type=scim_type, detail=detail)
|
|
273
|
+
|
|
274
|
+
@classmethod
|
|
275
|
+
def from_validation_errors(
|
|
276
|
+
cls, errors: ValidationError | Sequence[Mapping[str, Any]]
|
|
277
|
+
) -> list["Error"]:
|
|
278
|
+
"""Convert Pydantic validation errors to a list of SCIM Errors.
|
|
279
|
+
|
|
280
|
+
:param errors: A ``ValidationError`` or a list of error dicts.
|
|
281
|
+
:return: A list of SCIM Error objects.
|
|
282
|
+
"""
|
|
283
|
+
error_list = errors.errors() if isinstance(errors, ValidationError) else errors
|
|
284
|
+
return [cls.from_validation_error(error) for error in error_list]
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from typing import Annotated
|
|
2
1
|
from typing import Any
|
|
3
2
|
from typing import Generic
|
|
4
3
|
|
|
@@ -9,17 +8,15 @@ from pydantic import model_validator
|
|
|
9
8
|
from pydantic_core import PydanticCustomError
|
|
10
9
|
from typing_extensions import Self
|
|
11
10
|
|
|
12
|
-
from ..annotations import Required
|
|
13
11
|
from ..context import Context
|
|
12
|
+
from ..path import URN
|
|
14
13
|
from ..resources.resource import AnyResource
|
|
15
14
|
from .message import Message
|
|
16
15
|
from .message import _GenericMessageMetaclass
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
class ListResponse(Message, Generic[AnyResource], metaclass=_GenericMessageMetaclass):
|
|
20
|
-
|
|
21
|
-
"urn:ietf:params:scim:api:messages:2.0:ListResponse"
|
|
22
|
-
]
|
|
19
|
+
__schema__ = URN("urn:ietf:params:scim:api:messages:2.0:ListResponse")
|
|
23
20
|
|
|
24
21
|
total_results: int | None = None
|
|
25
22
|
"""The total number of results returned by the list or query operation."""
|
scim2_models/messages/message.py
CHANGED
|
@@ -7,11 +7,11 @@ from typing import get_origin
|
|
|
7
7
|
|
|
8
8
|
from pydantic import Discriminator
|
|
9
9
|
from pydantic import Tag
|
|
10
|
-
from pydantic._internal._model_construction import ModelMetaclass
|
|
11
10
|
|
|
12
11
|
from scim2_models.resources.resource import Resource
|
|
13
12
|
|
|
14
13
|
from ..base import BaseModel
|
|
14
|
+
from ..scim_object import ScimMetaclass
|
|
15
15
|
from ..scim_object import ScimObject
|
|
16
16
|
from ..utils import UNION_TYPES
|
|
17
17
|
|
|
@@ -56,7 +56,7 @@ def _get_tag(resource_type: type[BaseModel]) -> Tag:
|
|
|
56
56
|
:param resource_type: SCIM resource type
|
|
57
57
|
:return: Pydantic Tag for discrimination
|
|
58
58
|
"""
|
|
59
|
-
return Tag(resource_type
|
|
59
|
+
return Tag(getattr(resource_type, "__schema__", None) or "")
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
def _create_tagged_resource_union(resource_union: Any) -> Any:
|
|
@@ -75,7 +75,7 @@ def _create_tagged_resource_union(resource_union: Any) -> Any:
|
|
|
75
75
|
|
|
76
76
|
# Set up schemas for the discriminator function
|
|
77
77
|
resource_types_schemas = [
|
|
78
|
-
resource_type
|
|
78
|
+
getattr(resource_type, "__schema__", None) or ""
|
|
79
79
|
for resource_type in resource_types
|
|
80
80
|
]
|
|
81
81
|
|
|
@@ -92,7 +92,7 @@ def _create_tagged_resource_union(resource_union: Any) -> Any:
|
|
|
92
92
|
return Annotated[union, discriminator]
|
|
93
93
|
|
|
94
94
|
|
|
95
|
-
class _GenericMessageMetaclass(
|
|
95
|
+
class _GenericMessageMetaclass(ScimMetaclass):
|
|
96
96
|
"""Metaclass for SCIM generic types with discriminated unions."""
|
|
97
97
|
|
|
98
98
|
def __new__(
|