scim2-models 0.3.6__py3-none-any.whl → 0.3.7__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 +11 -11
- scim2_models/annotations.py +104 -0
- scim2_models/attributes.py +57 -0
- scim2_models/base.py +68 -525
- scim2_models/constants.py +3 -3
- scim2_models/context.py +168 -0
- scim2_models/reference.py +82 -0
- scim2_models/rfc7643/enterprise_user.py +4 -4
- scim2_models/rfc7643/group.py +5 -5
- scim2_models/rfc7643/resource.py +202 -95
- scim2_models/rfc7643/resource_type.py +13 -22
- scim2_models/rfc7643/schema.py +44 -38
- scim2_models/rfc7643/service_provider_config.py +7 -7
- scim2_models/rfc7643/user.py +9 -9
- scim2_models/rfc7644/bulk.py +2 -2
- scim2_models/rfc7644/error.py +11 -11
- scim2_models/rfc7644/list_response.py +5 -66
- scim2_models/rfc7644/message.py +103 -3
- scim2_models/rfc7644/patch_op.py +20 -6
- scim2_models/rfc7644/search_request.py +4 -4
- scim2_models/scim_object.py +143 -0
- scim2_models/utils.py +1 -1
- {scim2_models-0.3.6.dist-info → scim2_models-0.3.7.dist-info}/METADATA +1 -1
- scim2_models-0.3.7.dist-info/RECORD +29 -0
- scim2_models-0.3.6.dist-info/RECORD +0 -24
- {scim2_models-0.3.6.dist-info → scim2_models-0.3.7.dist-info}/WHEEL +0 -0
- {scim2_models-0.3.6.dist-info → scim2_models-0.3.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""Base SCIM object classes with schema identification."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
from typing import Annotated
|
|
5
|
+
from typing import Any
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
from .annotations import Required
|
|
9
|
+
from .base import BaseModel
|
|
10
|
+
from .context import Context
|
|
11
|
+
from .utils import normalize_attribute_name
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from .rfc7643.resource import Resource
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def validate_model_attribute(model: type["BaseModel"], attribute_base: str) -> None:
|
|
18
|
+
"""Validate that an attribute name or a sub-attribute path exist for a given model."""
|
|
19
|
+
attribute_name, *sub_attribute_blocks = attribute_base.split(".")
|
|
20
|
+
sub_attribute_base = ".".join(sub_attribute_blocks)
|
|
21
|
+
|
|
22
|
+
aliases = {field.validation_alias for field in model.model_fields.values()}
|
|
23
|
+
|
|
24
|
+
if normalize_attribute_name(attribute_name) not in aliases:
|
|
25
|
+
raise ValueError(
|
|
26
|
+
f"Model '{model.__name__}' has no attribute named '{attribute_name}'"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
if sub_attribute_base:
|
|
30
|
+
attribute_type = model.get_field_root_type(attribute_name)
|
|
31
|
+
|
|
32
|
+
if not attribute_type or not issubclass(attribute_type, BaseModel):
|
|
33
|
+
raise ValueError(
|
|
34
|
+
f"Attribute '{attribute_name}' is not a complex attribute, and cannot have a '{sub_attribute_base}' sub-attribute"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
validate_model_attribute(attribute_type, sub_attribute_base)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def extract_schema_and_attribute_base(attribute_urn: str) -> tuple[str, str]:
|
|
41
|
+
"""Extract the schema urn part and the attribute name part from attribute name.
|
|
42
|
+
|
|
43
|
+
As defined in :rfc:`RFC7644 §3.10 <7644#section-3.10>`.
|
|
44
|
+
"""
|
|
45
|
+
*urn_blocks, attribute_base = attribute_urn.split(":")
|
|
46
|
+
schema = ":".join(urn_blocks)
|
|
47
|
+
return schema, attribute_base
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def validate_attribute_urn(
|
|
51
|
+
attribute_name: str,
|
|
52
|
+
default_resource: Optional[type["Resource"]] = None,
|
|
53
|
+
resource_types: Optional[list[type["Resource"]]] = None,
|
|
54
|
+
) -> str:
|
|
55
|
+
"""Validate that an attribute urn is valid or not.
|
|
56
|
+
|
|
57
|
+
:param attribute_name: The attribute urn to check.
|
|
58
|
+
:default_resource: The default resource if `attribute_name` is not an absolute urn.
|
|
59
|
+
:resource_types: The available resources in which to look for the attribute.
|
|
60
|
+
:return: The normalized attribute URN.
|
|
61
|
+
"""
|
|
62
|
+
from .rfc7643.resource import Resource
|
|
63
|
+
|
|
64
|
+
if not resource_types:
|
|
65
|
+
resource_types = []
|
|
66
|
+
|
|
67
|
+
if default_resource and default_resource not in resource_types:
|
|
68
|
+
resource_types.append(default_resource)
|
|
69
|
+
|
|
70
|
+
default_schema = (
|
|
71
|
+
default_resource.model_fields["schemas"].default[0]
|
|
72
|
+
if default_resource
|
|
73
|
+
else None
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
schema: Optional[Any]
|
|
77
|
+
schema, attribute_base = extract_schema_and_attribute_base(attribute_name)
|
|
78
|
+
if not schema:
|
|
79
|
+
schema = default_schema
|
|
80
|
+
|
|
81
|
+
if not schema:
|
|
82
|
+
raise ValueError("No default schema and relative URN")
|
|
83
|
+
|
|
84
|
+
resource = Resource.get_by_schema(resource_types, schema)
|
|
85
|
+
if not resource:
|
|
86
|
+
raise ValueError(f"No resource matching schema '{schema}'")
|
|
87
|
+
|
|
88
|
+
validate_model_attribute(resource, attribute_base)
|
|
89
|
+
|
|
90
|
+
return f"{schema}:{attribute_base}"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class ScimObject(BaseModel):
|
|
94
|
+
schemas: Annotated[list[str], Required.true]
|
|
95
|
+
"""The "schemas" attribute is a REQUIRED attribute and is an array of
|
|
96
|
+
Strings containing URIs that are used to indicate the namespaces of the
|
|
97
|
+
SCIM schemas that define the attributes present in the current JSON
|
|
98
|
+
structure."""
|
|
99
|
+
|
|
100
|
+
def _prepare_model_dump(
|
|
101
|
+
self,
|
|
102
|
+
scim_ctx: Optional[Context] = Context.DEFAULT,
|
|
103
|
+
**kwargs: Any,
|
|
104
|
+
) -> dict[str, Any]:
|
|
105
|
+
kwargs.setdefault("context", {}).setdefault("scim", scim_ctx)
|
|
106
|
+
|
|
107
|
+
if scim_ctx:
|
|
108
|
+
kwargs.setdefault("exclude_none", True)
|
|
109
|
+
kwargs.setdefault("by_alias", True)
|
|
110
|
+
|
|
111
|
+
return kwargs
|
|
112
|
+
|
|
113
|
+
def model_dump(
|
|
114
|
+
self,
|
|
115
|
+
*args: Any,
|
|
116
|
+
scim_ctx: Optional[Context] = Context.DEFAULT,
|
|
117
|
+
**kwargs: Any,
|
|
118
|
+
) -> dict[str, Any]:
|
|
119
|
+
"""Create a model representation that can be included in SCIM messages by using Pydantic :code:`BaseModel.model_dump`.
|
|
120
|
+
|
|
121
|
+
:param scim_ctx: If a SCIM context is passed, some default values of
|
|
122
|
+
Pydantic :code:`BaseModel.model_dump` are tuned to generate valid SCIM
|
|
123
|
+
messages. Pass :data:`None` to get the default Pydantic behavior.
|
|
124
|
+
"""
|
|
125
|
+
dump_kwargs = self._prepare_model_dump(scim_ctx, **kwargs)
|
|
126
|
+
if scim_ctx:
|
|
127
|
+
dump_kwargs.setdefault("mode", "json")
|
|
128
|
+
return super(BaseModel, self).model_dump(*args, **dump_kwargs)
|
|
129
|
+
|
|
130
|
+
def model_dump_json(
|
|
131
|
+
self,
|
|
132
|
+
*args: Any,
|
|
133
|
+
scim_ctx: Optional[Context] = Context.DEFAULT,
|
|
134
|
+
**kwargs: Any,
|
|
135
|
+
) -> str:
|
|
136
|
+
"""Create a JSON model representation that can be included in SCIM messages by using Pydantic :code:`BaseModel.model_dump_json`.
|
|
137
|
+
|
|
138
|
+
:param scim_ctx: If a SCIM context is passed, some default values of
|
|
139
|
+
Pydantic :code:`BaseModel.model_dump` are tuned to generate valid SCIM
|
|
140
|
+
messages. Pass :data:`None` to get the default Pydantic behavior.
|
|
141
|
+
"""
|
|
142
|
+
dump_kwargs = self._prepare_model_dump(scim_ctx, **kwargs)
|
|
143
|
+
return super(BaseModel, self).model_dump_json(*args, **dump_kwargs)
|
scim2_models/utils.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scim2-models
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.7
|
|
4
4
|
Summary: SCIM2 models serialization and validation with pydantic
|
|
5
5
|
Project-URL: documentation, https://scim2-models.readthedocs.io
|
|
6
6
|
Project-URL: repository, https://github.com/python-scim/scim2-models
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
scim2_models/__init__.py,sha256=yqYNm1B18OD-c8Y3QC3VWWv6Yoxw4PAvpC9eABhxef0,3128
|
|
2
|
+
scim2_models/annotations.py,sha256=oRjlKL1fqrYfa9UtaMdxF5fOT8CUUN3m-rdzvf7aiSA,3304
|
|
3
|
+
scim2_models/attributes.py,sha256=VloM7txtM2oexPrHO4phVY6nDzORMr3Vqf6EFAEZzyk,1804
|
|
4
|
+
scim2_models/base.py,sha256=BcAjsbwaHhO8AnGJJF05MqfL636UBlM2njFuCvFL_SY,16795
|
|
5
|
+
scim2_models/constants.py,sha256=9egq8JW0dFAqPng85CiHoH5T6pRtYL87-gC0C-IMGsk,573
|
|
6
|
+
scim2_models/context.py,sha256=oV8BCBSl9NvXuue11q4EYnoSze1yqtja9U_HEdrR-88,9125
|
|
7
|
+
scim2_models/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
scim2_models/reference.py,sha256=EQM8bbSr_kxbFMNlWYf_4sAJlSsOS5wUrn-9_eF0Ykc,2483
|
|
9
|
+
scim2_models/scim_object.py,sha256=t1p6ha719w1YU2Gtcy_k2NY-X0kc8PJxwstKOGP0oPA,5183
|
|
10
|
+
scim2_models/utils.py,sha256=1fmJoVCtrFURmvBegGti8UnXdj9EnzkNmg83jtpj70A,2755
|
|
11
|
+
scim2_models/rfc7643/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
scim2_models/rfc7643/enterprise_user.py,sha256=TVa5aS-eLHcDkwyr58hZYsRKk0AwjUaUaSFhU51mn5E,1806
|
|
13
|
+
scim2_models/rfc7643/group.py,sha256=lJXKopa__LoWhkaNqu0JFVyQaOMe-AF4vISaq0Gg7cE,1458
|
|
14
|
+
scim2_models/rfc7643/resource.py,sha256=jPP6nGGEVOLIX7Zmka5xHLGk3jJBfpaMBPizU1mXFoo,17275
|
|
15
|
+
scim2_models/rfc7643/resource_type.py,sha256=scLqbD3HX3fXT2JOXY9OUVnZz7i5ty2lx4VuiVxt6DE,3314
|
|
16
|
+
scim2_models/rfc7643/schema.py,sha256=DJQvDx31jYYZyfS3noTu4-8C429u0ctUqRysmvUULyI,10647
|
|
17
|
+
scim2_models/rfc7643/service_provider_config.py,sha256=6xJ182T-1szEQnN5Zb1cTdQCgTYIFi4XKygbvDlTKTM,5446
|
|
18
|
+
scim2_models/rfc7643/user.py,sha256=ErOghhilUF7fipwDRqARyLwJhbntQx4GJG3u2sZNJXs,10664
|
|
19
|
+
scim2_models/rfc7644/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
+
scim2_models/rfc7644/bulk.py,sha256=ZVGtitEDy--iDBzU2WR-LT7_rIizZFBD3sOo6rJ_WII,2590
|
|
21
|
+
scim2_models/rfc7644/error.py,sha256=KZBJfI2z4TByAK6W3mN3e3m0ZrDguPLm66v9W971Awk,6302
|
|
22
|
+
scim2_models/rfc7644/list_response.py,sha256=8o1_WR3AOZNv0hbCGcgq8lyeXaNjo1CiLxfteq8gctk,2396
|
|
23
|
+
scim2_models/rfc7644/message.py,sha256=rX2KezTdM81Z9mw7JTJYjWF-VDnDeUm6-ZxsarmVdsE,3738
|
|
24
|
+
scim2_models/rfc7644/patch_op.py,sha256=Yk2qr-vsuU6MMh6uFijo3Tw1vgo-clbgj1T0B8S1Tcs,2856
|
|
25
|
+
scim2_models/rfc7644/search_request.py,sha256=kLhIfyjAjc7ar6wkT7t-A2ySB-_3XYP-gf_LspLU2RU,3063
|
|
26
|
+
scim2_models-0.3.7.dist-info/METADATA,sha256=tqCuz5S5ESdKVlEQhpsOVxgXHUDfUyAC32rkIOH1w98,16288
|
|
27
|
+
scim2_models-0.3.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
28
|
+
scim2_models-0.3.7.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
29
|
+
scim2_models-0.3.7.dist-info/RECORD,,
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
scim2_models/__init__.py,sha256=Y06vTA_51lXfv9zk_dTzyIIqEo1H2bcencvMM5KAwn8,3063
|
|
2
|
-
scim2_models/base.py,sha256=NV-uaDWG_pN6Cl_PT1E9PqdG7QH7jMMADGi3PVVurHQ,34917
|
|
3
|
-
scim2_models/constants.py,sha256=SuMGFtVNletdV5ZJRUcIq7o2CqZCRvOurnIdLE_cakE,540
|
|
4
|
-
scim2_models/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
scim2_models/utils.py,sha256=MzZz212-lkVWgXcpXvNwoi_u28wBTpkTwPrfYC5v92A,2771
|
|
6
|
-
scim2_models/rfc7643/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
-
scim2_models/rfc7643/enterprise_user.py,sha256=EaxdHH2dcBrwWwGpaZC6iZ9dbcaVN1NpoRLAdkTYssQ,1781
|
|
8
|
-
scim2_models/rfc7643/group.py,sha256=JML8OtgKjvHHv2YufiYcTtbZuN5GFVQTbm1J6MLtp8o,1427
|
|
9
|
-
scim2_models/rfc7643/resource.py,sha256=oEm0RVBFonTrrhS-iYQquAdiy4UW4nXHbk_Bf--fR3g,12849
|
|
10
|
-
scim2_models/rfc7643/resource_type.py,sha256=vT2ItHvBzmsFVt3zbIJABxjcnSLUK-mW-zWduHxGE3k,3570
|
|
11
|
-
scim2_models/rfc7643/schema.py,sha256=B7TzMbT6ngYQrMqvqW5_LberN6EaqtZaFwBVsgoA3S0,10388
|
|
12
|
-
scim2_models/rfc7643/service_provider_config.py,sha256=deMNCXlqiNzuLcVRN9mdHiTUxhczDnvi-oO6k-Anj8U,5402
|
|
13
|
-
scim2_models/rfc7643/user.py,sha256=EEje4V_zbMVwVYOu2Gj1W7GjD90WnC0lUK3FJuh4jWE,10607
|
|
14
|
-
scim2_models/rfc7644/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
scim2_models/rfc7644/bulk.py,sha256=I6S40kyJPwDQwPFi668wFFDVTST7z6QTe9HTL5QUViI,2577
|
|
16
|
-
scim2_models/rfc7644/error.py,sha256=l4-vtGQYm5u13-ParhbHSeqXEil0E09QXSO9twAT3SU,6185
|
|
17
|
-
scim2_models/rfc7644/list_response.py,sha256=GNfRKpL2WK2KHGC3kg7ldaSiPwCXl0AxDfhnbHByEAY,4589
|
|
18
|
-
scim2_models/rfc7644/message.py,sha256=F4kPqbHAka3-wZzap9a45noQZw-o1vznTJypNABBF7w,253
|
|
19
|
-
scim2_models/rfc7644/patch_op.py,sha256=OE-ixDanTkY5zQP7EK7OAp88uE_fMk03mqmaZHxgJ-g,2210
|
|
20
|
-
scim2_models/rfc7644/search_request.py,sha256=DRGlixcWtYtbUuP9MT7PsnvyxlONLcXGEcQveWdqQng,3003
|
|
21
|
-
scim2_models-0.3.6.dist-info/METADATA,sha256=ihhjxgKo0dF-ufWhrgCdsNiH6vGXOplFlga07UVHrLw,16288
|
|
22
|
-
scim2_models-0.3.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
23
|
-
scim2_models-0.3.6.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
24
|
-
scim2_models-0.3.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|