scim2-client 0.1.2__tar.gz → 0.1.4__tar.gz
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_client-0.1.2 → scim2_client-0.1.4}/PKG-INFO +4 -3
- {scim2_client-0.1.2 → scim2_client-0.1.4}/README.md +2 -1
- {scim2_client-0.1.2 → scim2_client-0.1.4}/pyproject.toml +2 -2
- {scim2_client-0.1.2 → scim2_client-0.1.4}/scim2_client/client.py +42 -8
- {scim2_client-0.1.2 → scim2_client-0.1.4}/scim2_client/__init__.py +0 -0
- {scim2_client-0.1.2 → scim2_client-0.1.4}/scim2_client/errors.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: scim2-client
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Pythonically build SCIM requests and parse SCIM responses
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: scim,scim2,provisioning,httpx,api
|
|
@@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
21
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
22
22
|
Requires-Dist: httpx (>=0.27.0,<0.28.0)
|
|
23
|
-
Requires-Dist: scim2-models (>=0.1.
|
|
23
|
+
Requires-Dist: scim2-models (>=0.1.2,<0.2.0)
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
25
25
|
|
|
26
26
|
# scim2-client
|
|
@@ -65,7 +65,8 @@ assert user.meta.last_updated == datetime.datetime(
|
|
|
65
65
|
)
|
|
66
66
|
|
|
67
67
|
# Create resources
|
|
68
|
-
|
|
68
|
+
payload = User(user_name="bjensen@example.com")
|
|
69
|
+
response = scim.create(user)
|
|
69
70
|
assert isinstance(response, Error)
|
|
70
71
|
assert response.detail == "One or more of the attribute values are already in use or are reserved."
|
|
71
72
|
```
|
|
@@ -40,7 +40,8 @@ assert user.meta.last_updated == datetime.datetime(
|
|
|
40
40
|
)
|
|
41
41
|
|
|
42
42
|
# Create resources
|
|
43
|
-
|
|
43
|
+
payload = User(user_name="bjensen@example.com")
|
|
44
|
+
response = scim.create(user)
|
|
44
45
|
assert isinstance(response, Error)
|
|
45
46
|
assert response.detail == "One or more of the attribute values are already in use or are reserved."
|
|
46
47
|
```
|
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[tool.poetry]
|
|
6
6
|
name = "scim2-client"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.4"
|
|
8
8
|
description = "Pythonically build SCIM requests and parse SCIM responses"
|
|
9
9
|
authors = ["Yaal Coop <contact@yaal.coop>"]
|
|
10
10
|
license = "MIT"
|
|
@@ -27,7 +27,7 @@ classifiers = [
|
|
|
27
27
|
[tool.poetry.dependencies]
|
|
28
28
|
python = "^3.9"
|
|
29
29
|
httpx = "^0.27.0"
|
|
30
|
-
scim2-models = "^0.1.
|
|
30
|
+
scim2-models = "^0.1.2"
|
|
31
31
|
|
|
32
32
|
[tool.poetry.group.doc]
|
|
33
33
|
optional = true
|
|
@@ -15,8 +15,10 @@ from scim2_models import Context
|
|
|
15
15
|
from scim2_models import Error
|
|
16
16
|
from scim2_models import ListResponse
|
|
17
17
|
from scim2_models import PatchOp
|
|
18
|
+
from scim2_models import Resource
|
|
18
19
|
from scim2_models import SearchRequest
|
|
19
20
|
|
|
21
|
+
from .errors import SCIMClientError
|
|
20
22
|
from .errors import UnexpectedContentFormat
|
|
21
23
|
from .errors import UnexpectedContentType
|
|
22
24
|
from .errors import UnexpectedStatusCode
|
|
@@ -104,7 +106,12 @@ class SCIMClient:
|
|
|
104
106
|
raise ValueError(f"Unknown resource type: '{resource_type}'")
|
|
105
107
|
|
|
106
108
|
def resource_endpoint(self, resource_type: Type):
|
|
107
|
-
|
|
109
|
+
try:
|
|
110
|
+
first_bracket_index = resource_type.__name__.index("[")
|
|
111
|
+
root_name = resource_type.__name__[:first_bracket_index]
|
|
112
|
+
except ValueError:
|
|
113
|
+
root_name = resource_type.__name__
|
|
114
|
+
return f"/{root_name}s"
|
|
108
115
|
|
|
109
116
|
def check_response(
|
|
110
117
|
self,
|
|
@@ -166,6 +173,7 @@ class SCIMClient:
|
|
|
166
173
|
<7644#section-3.3>`.
|
|
167
174
|
|
|
168
175
|
:param resource: The resource to create
|
|
176
|
+
If is a :data:`dict`, the resource type will be guessed from the schema.
|
|
169
177
|
:param check_request_payload: If :data:`False`,
|
|
170
178
|
:code:`resource` is expected to be a dict that will be passed as-is in the request.
|
|
171
179
|
:param check_response_payload: Whether to validate that the response payload is valid.
|
|
@@ -184,8 +192,20 @@ class SCIMClient:
|
|
|
184
192
|
url = kwargs.pop("url", None)
|
|
185
193
|
|
|
186
194
|
else:
|
|
187
|
-
|
|
188
|
-
|
|
195
|
+
if isinstance(resource, Resource):
|
|
196
|
+
resource_type = resource.__class__
|
|
197
|
+
|
|
198
|
+
else:
|
|
199
|
+
resource_type = Resource.get_by_payload(self.resource_types, resource)
|
|
200
|
+
if not resource_type:
|
|
201
|
+
raise SCIMClientError(
|
|
202
|
+
None, "Cannot guess resource type from the payload"
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
resource = resource_type.model_validate(resource)
|
|
206
|
+
|
|
207
|
+
self.check_resource_type(resource_type)
|
|
208
|
+
url = kwargs.pop("url", self.resource_endpoint(resource_type))
|
|
189
209
|
payload = resource.model_dump(scim_ctx=Context.RESOURCE_CREATION_REQUEST)
|
|
190
210
|
|
|
191
211
|
response = self.client.post(url, json=payload, **kwargs)
|
|
@@ -352,7 +372,7 @@ class SCIMClient:
|
|
|
352
372
|
else None
|
|
353
373
|
)
|
|
354
374
|
|
|
355
|
-
response = self.client.post("/.search",
|
|
375
|
+
response = self.client.post("/.search", json=payload)
|
|
356
376
|
|
|
357
377
|
return self.check_response(
|
|
358
378
|
response,
|
|
@@ -397,7 +417,8 @@ class SCIMClient:
|
|
|
397
417
|
"""Perform a PUT request to replace a resource, as defined in
|
|
398
418
|
:rfc:`RFC7644 §3.5.1 <7644#section-3.5.1>`.
|
|
399
419
|
|
|
400
|
-
:param resource: The new
|
|
420
|
+
:param resource: The new resource to replace.
|
|
421
|
+
If is a :data:`dict`, the resource type will be guessed from the schema.
|
|
401
422
|
:param check_request_payload: If :data:`False`,
|
|
402
423
|
:code:`resource` is expected to be a dict that will be passed as-is in the request.
|
|
403
424
|
:param check_response_payload: Whether to validate that the response payload is valid.
|
|
@@ -413,12 +434,25 @@ class SCIMClient:
|
|
|
413
434
|
|
|
414
435
|
if not check_request_payload:
|
|
415
436
|
payload = resource
|
|
416
|
-
url = kwargs.pop("url")
|
|
437
|
+
url = kwargs.pop("url", None)
|
|
417
438
|
|
|
418
439
|
else:
|
|
419
|
-
|
|
440
|
+
if isinstance(resource, Resource):
|
|
441
|
+
resource_type = resource.__class__
|
|
442
|
+
|
|
443
|
+
else:
|
|
444
|
+
resource_type = Resource.get_by_payload(self.resource_types, resource)
|
|
445
|
+
if not resource_type:
|
|
446
|
+
raise SCIMClientError(
|
|
447
|
+
None, "Cannot guess resource type from the payload"
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
resource = resource_type.model_validate(resource)
|
|
451
|
+
|
|
452
|
+
self.check_resource_type(resource_type)
|
|
453
|
+
|
|
420
454
|
if not resource.id:
|
|
421
|
-
raise
|
|
455
|
+
raise SCIMClientError(None, "Resource must have an id")
|
|
422
456
|
|
|
423
457
|
payload = resource.model_dump(scim_ctx=Context.RESOURCE_REPLACEMENT_REQUEST)
|
|
424
458
|
url = kwargs.pop(
|
|
File without changes
|
|
File without changes
|