scim2-models 0.6.2__py3-none-any.whl → 0.6.3__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/path.py CHANGED
@@ -9,6 +9,8 @@ from typing import NamedTuple
9
9
  from typing import TypeVar
10
10
 
11
11
  from pydantic import GetCoreSchemaHandler
12
+ from pydantic import GetJsonSchemaHandler
13
+ from pydantic.json_schema import JsonSchemaValue
12
14
  from pydantic_core import core_schema
13
15
 
14
16
  from .base import BaseModel
@@ -129,6 +131,14 @@ class Path(UserString, Generic[ResourceT]):
129
131
  serialization=core_schema.plain_serializer_function_ser_schema(str),
130
132
  )
131
133
 
134
+ @classmethod
135
+ def __get_pydantic_json_schema__(
136
+ cls,
137
+ _core_schema: core_schema.CoreSchema,
138
+ _handler: GetJsonSchemaHandler,
139
+ ) -> JsonSchemaValue:
140
+ return {"type": "string"}
141
+
132
142
  def __init__(self, path: "str | Path[Any]"):
133
143
  if isinstance(path, Path):
134
144
  path = str(path)
scim2_models/reference.py CHANGED
@@ -7,6 +7,8 @@ from typing import get_args
7
7
  from typing import get_origin
8
8
 
9
9
  from pydantic import GetCoreSchemaHandler
10
+ from pydantic import GetJsonSchemaHandler
11
+ from pydantic.json_schema import JsonSchemaValue
10
12
  from pydantic_core import Url
11
13
  from pydantic_core import ValidationError
12
14
  from pydantic_core import core_schema
@@ -112,6 +114,14 @@ class Reference(str, Generic[ReferenceTypes]):
112
114
  serialization=core_schema.plain_serializer_function_ser_schema(str),
113
115
  )
114
116
 
117
+ @classmethod
118
+ def __get_pydantic_json_schema__(
119
+ cls,
120
+ _core_schema: core_schema.CoreSchema,
121
+ _handler: GetJsonSchemaHandler,
122
+ ) -> JsonSchemaValue:
123
+ return {"type": "string", "format": "uri"}
124
+
115
125
  @classmethod
116
126
  def get_scim_reference_types(cls) -> list[str]:
117
127
  """Return referenceTypes for SCIM schema generation."""
@@ -3,6 +3,7 @@ from typing import Annotated
3
3
 
4
4
  from pydantic import Field
5
5
 
6
+ from ..annotations import CaseExact
6
7
  from ..annotations import Mutability
7
8
  from ..annotations import Required
8
9
  from ..attributes import ComplexAttribute
@@ -15,7 +16,7 @@ if TYPE_CHECKING:
15
16
 
16
17
 
17
18
  class Manager(ComplexAttribute):
18
- value: Annotated[str | None, Required.true] = None
19
+ value: Annotated[str | None, Required.true, CaseExact.true] = None
19
20
  """The id of the SCIM resource representing the User's manager."""
20
21
 
21
22
  ref: Annotated[ # type: ignore[type-arg]
@@ -7,6 +7,7 @@ from typing import Union
7
7
  from pydantic import Field
8
8
 
9
9
  from ..annotations import Mutability
10
+ from ..annotations import Required
10
11
  from ..attributes import ComplexAttribute
11
12
  from ..path import URN
12
13
  from ..reference import Reference
@@ -38,7 +39,7 @@ class GroupMember(ComplexAttribute):
38
39
  class Group(Resource[Any]):
39
40
  __schema__ = URN("urn:ietf:params:scim:schemas:core:2.0:Group")
40
41
 
41
- display_name: str | None = None
42
+ display_name: Annotated[str | None, Required.true] = None
42
43
  """A human-readable name for the Group."""
43
44
 
44
45
  members: list[GroupMember] | None = None
@@ -532,19 +532,21 @@ def _model_attribute_to_scim_attribute(
532
532
  else None
533
533
  )
534
534
 
535
- return Attribute(
536
- name=field_info.serialization_alias or attribute_name,
537
- type=Attribute.Type(attribute_type),
538
- multi_valued=model.get_field_multiplicity(attribute_name),
539
- description=field_info.description,
540
- canonical_values=field_info.examples,
541
- required=model.get_field_annotation(attribute_name, Required),
542
- case_exact=model.get_field_annotation(attribute_name, CaseExact),
543
- mutability=model.get_field_annotation(attribute_name, Mutability),
544
- returned=model.get_field_annotation(attribute_name, Returned),
545
- uniqueness=model.get_field_annotation(attribute_name, Uniqueness),
546
- sub_attributes=sub_attributes,
547
- reference_types=root_type.get_scim_reference_types() # type: ignore[attr-defined]
548
- if attribute_type == Attribute.Type.reference
549
- else None,
550
- )
535
+ kwargs: dict[str, Any] = {
536
+ "name": field_info.serialization_alias or attribute_name,
537
+ "type": Attribute.Type(attribute_type),
538
+ "multi_valued": model.get_field_multiplicity(attribute_name),
539
+ "description": field_info.description,
540
+ "canonical_values": field_info.examples,
541
+ "required": model.get_field_annotation(attribute_name, Required),
542
+ "case_exact": model.get_field_annotation(attribute_name, CaseExact),
543
+ "mutability": model.get_field_annotation(attribute_name, Mutability),
544
+ "returned": model.get_field_annotation(attribute_name, Returned),
545
+ "sub_attributes": sub_attributes,
546
+ }
547
+ if attribute_type != Attribute.Type.complex:
548
+ kwargs["uniqueness"] = model.get_field_annotation(attribute_name, Uniqueness)
549
+ if attribute_type == Attribute.Type.reference:
550
+ kwargs["reference_types"] = root_type.get_scim_reference_types() # type: ignore[attr-defined]
551
+
552
+ return Attribute(**kwargs)
@@ -8,6 +8,7 @@ from ..annotations import CaseExact
8
8
  from ..annotations import Mutability
9
9
  from ..annotations import Required
10
10
  from ..annotations import Returned
11
+ from ..annotations import Uniqueness
11
12
  from ..attributes import ComplexAttribute
12
13
  from ..path import URN
13
14
  from ..reference import URI
@@ -38,7 +39,13 @@ class SchemaExtension(ComplexAttribute):
38
39
  class ResourceType(Resource[Any]):
39
40
  __schema__ = URN("urn:ietf:params:scim:schemas:core:2.0:ResourceType")
40
41
 
41
- name: Annotated[str | None, Mutability.read_only, Required.true] = None
42
+ name: Annotated[
43
+ str | None,
44
+ Mutability.read_only,
45
+ Required.true,
46
+ CaseExact.true,
47
+ Uniqueness.server,
48
+ ] = None
42
49
  """The resource type name.
43
50
 
44
51
  When applicable, service providers MUST specify the name, e.g.,
@@ -57,9 +64,9 @@ class ResourceType(Resource[Any]):
57
64
  This is often the same value as the "name" attribute.
58
65
  """
59
66
 
60
- endpoint: Annotated[Reference[URI] | None, Mutability.read_only, Required.true] = (
61
- None
62
- )
67
+ endpoint: Annotated[
68
+ Reference[URI] | None, Mutability.read_only, Required.true, Uniqueness.server
69
+ ] = None
63
70
  """The resource type's HTTP-addressable endpoint relative to the Base URL,
64
71
  e.g., '/Users'."""
65
72
 
@@ -2,7 +2,6 @@ from enum import Enum
2
2
  from typing import TYPE_CHECKING
3
3
  from typing import Annotated
4
4
  from typing import ClassVar
5
- from typing import Union
6
5
 
7
6
  from pydantic import Base64Bytes
8
7
  from pydantic import EmailStr
@@ -202,8 +201,8 @@ class GroupMembership(ComplexAttribute):
202
201
  value: Annotated[str | None, Mutability.read_only] = None
203
202
  """The identifier of the User's group."""
204
203
 
205
- ref: Annotated[ # type: ignore[type-arg]
206
- Reference[Union["User", "Group"]] | None,
204
+ ref: Annotated[
205
+ Reference["Group"] | None,
207
206
  Mutability.read_only,
208
207
  ] = Field(None, serialization_alias="$ref")
209
208
  """The reference URI of a target resource, if the attribute is a
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: scim2-models
3
- Version: 0.6.2
3
+ Version: 0.6.3
4
4
  Summary: SCIM2 models serialization and validation with pydantic
5
5
  Keywords: scim,scim2,provisioning,pydantic,rfc7643,rfc7644
6
6
  Author: Yaal Coop
@@ -240,6 +240,17 @@ Provisioning is the action of managing a set of resources across different servi
240
240
  SCIM is often used between Identity Providers and applications in completion of standards like OAuth2 and OpenID Connect.
241
241
  It allows users and groups creations, modifications and deletions to be synchronized between applications.
242
242
 
243
+ ## Features
244
+
245
+ - **SCIM Resources**: Native Python classes for `User`, `Group`, `EnterpriseUser`, `ServiceProviderConfig`, `ResourceType` and `Schema`
246
+ - **Pydantic Integration**: Full Pydantic v2 support with validation, serialization and IDE autocompletion
247
+ - **RFC Compliance**: Implements [RFC7643](https://datatracker.ietf.org/doc/html/rfc7643) (schema) and [RFC7644](https://datatracker.ietf.org/doc/html/rfc7644) (protocol) specifications
248
+ - **Attribute Metadata**: Support for `Mutability`, `Returned`, `Uniqueness` and `Required` field annotations
249
+ - **Context-Aware Validation**: Automatic field inclusion/exclusion based on HTTP context (creation, query, replacement, etc.)
250
+ - **Schema Extensions**: Dynamic schema extensions and custom resource types, dynamic conversion between schemas and Python models.
251
+ - **SCIM Messages**: `ListResponse`, `SearchRequest`, `PatchOp`, and `Error` messages
252
+ - **Error Handling**: SCIM-compliant exceptions with automatic conversion to `Error` responses
253
+
243
254
  ## Installation
244
255
 
245
256
  ```shell
@@ -12,19 +12,19 @@ scim2_models/messages/list_response.py,sha256=ahAqdElGSNxt8LlOUeSsNbOykZdCLM4aJy
12
12
  scim2_models/messages/message.py,sha256=7svNN_xi8BSyWmRoMdYFTjQGuV1F9HUpQYHb6TQtf8A,4081
13
13
  scim2_models/messages/patch_op.py,sha256=QwAkeHvzzUXFmS8Ut_ns99yhiSQehpuHAodI_eSc_hA,16236
14
14
  scim2_models/messages/search_request.py,sha256=OXw4-oehLC5NyD7yVFEq0QgPsxAaQwXE7hZMKiNkvzY,3017
15
- scim2_models/path.py,sha256=4u-Lqtq8lqSmJUi6thFDwhpzc-uzyVFulsTklIyIFL8,27053
15
+ scim2_models/path.py,sha256=LwAhBtLQg4dKveRgvsj1R20ptT8mK9x9UfEczBWQuKE,27359
16
16
  scim2_models/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- scim2_models/reference.py,sha256=-E6VD-lFPEIXpSpwu0G_3MKLbWKgZhwk8ER3-JhCHig,5636
17
+ scim2_models/reference.py,sha256=Nx9r19EZ8ET7x1KvmHzyhJ4UH8n1GUsJAerezmZ52PI,5959
18
18
  scim2_models/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- scim2_models/resources/enterprise_user.py,sha256=Wk8CzQrCXUE-roQYINpj4YhOlj2s_TD3Y3SnEXK6jKY,1798
20
- scim2_models/resources/group.py,sha256=nmmPlbP7gQluNJEtFIFYtjDYJ2AR4Uml5LuxMcY_NIk,1379
21
- scim2_models/resources/resource.py,sha256=0Y8xloQk6tWQ9L7gW__qlUkU55mpYAsxfpeuFuSX2Vk,20550
22
- scim2_models/resources/resource_type.py,sha256=IDzUcv9_XiAHOpaaG9j24sa-nNKY6i0wPDTTrxNqJgQ,3297
19
+ scim2_models/resources/enterprise_user.py,sha256=4y6AyoIzGdXYeTpoBb5gJmLmXBK8xac6-GBZ-5fbytM,1850
20
+ scim2_models/resources/group.py,sha256=_BA0Qxr7QBjH_1nNrRVi6kbYjBAd86x2cvsVgP3iMHM,1440
21
+ scim2_models/resources/resource.py,sha256=IDJsrXzzPC5OA93hNeoPknDbLfIbISozBEf1XQfvjyU,20671
22
+ scim2_models/resources/resource_type.py,sha256=yO18uO04eaWJ0yFdvtzI0cfjpr0545aFM3gAYBIw2MI,3433
23
23
  scim2_models/resources/schema.py,sha256=wDh8G1oxCgyQcmChz30bVNPjyksYcgxD66k0mB1VIdI,10239
24
24
  scim2_models/resources/service_provider_config.py,sha256=cmfPtLPOuwNrZl9hGpbrMsQhoOwIytlf2Q_LAJegAcQ,5303
25
- scim2_models/resources/user.py,sha256=Z-h8x9dAnxBqDeZJbKi-u-HCv6aQdS8e4VzHLVm63ZA,11398
25
+ scim2_models/resources/user.py,sha256=uIUlEV4h1LsqWHLXvHVZWdx5H5n4X4kKknNzR15V72c,11332
26
26
  scim2_models/scim_object.py,sha256=suYhQ0iFQs1aKTlSerWZsi_sAVhFX_9N24U_DmZxCbw,5321
27
27
  scim2_models/utils.py,sha256=Lb7mlP3I_IfAlqi_8_m4G-_1Rn7oKRqbNdpoDLjXXr0,1978
28
- scim2_models-0.6.2.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
29
- scim2_models-0.6.2.dist-info/METADATA,sha256=q6LTJlB0nesIAO3-DP7Exy2cw4IbODc8MxGRTydt7Qw,16486
30
- scim2_models-0.6.2.dist-info/RECORD,,
28
+ scim2_models-0.6.3.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
29
+ scim2_models-0.6.3.dist-info/METADATA,sha256=DwqVdSFbzm9gp0MkXayievlAEArR_YTjHGWQ-7m2Ylw,17479
30
+ scim2_models-0.6.3.dist-info/RECORD,,