scim2-client 0.1.0__tar.gz → 0.1.1__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.0 → scim2_client-0.1.1}/PKG-INFO +5 -3
- {scim2_client-0.1.0 → scim2_client-0.1.1}/README.md +3 -1
- {scim2_client-0.1.0 → scim2_client-0.1.1}/pyproject.toml +2 -2
- {scim2_client-0.1.0 → scim2_client-0.1.1}/scim2_client/client.py +36 -11
- {scim2_client-0.1.0 → scim2_client-0.1.1}/scim2_client/__init__.py +0 -0
- {scim2_client-0.1.0 → scim2_client-0.1.1}/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.1
|
|
4
4
|
Summary: Pythonically build SCIM requests and parse SCIM responses
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: scim,scim2,provisioning,httpx,api
|
|
@@ -20,12 +20,14 @@ 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.1,<0.2.0)
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
25
25
|
|
|
26
26
|
# scim2-client
|
|
27
27
|
|
|
28
|
-
A SCIM client library built upon [scim2-models](https://scim2-models.readthedocs.io)
|
|
28
|
+
A SCIM client Python library built upon [scim2-models](https://scim2-models.readthedocs.io) and [httpx](https://github.com/encode/httpx),
|
|
29
|
+
that pythonically build requests and parse responses,
|
|
30
|
+
following the [RFC7643](https://datatracker.ietf.org/doc/html/rfc7643.html) and [RFC7644](https://datatracker.ietf.org/doc/html/rfc7644.html) specifications.
|
|
29
31
|
## Installation
|
|
30
32
|
|
|
31
33
|
```shell
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# scim2-client
|
|
2
2
|
|
|
3
|
-
A SCIM client library built upon [scim2-models](https://scim2-models.readthedocs.io)
|
|
3
|
+
A SCIM client Python library built upon [scim2-models](https://scim2-models.readthedocs.io) and [httpx](https://github.com/encode/httpx),
|
|
4
|
+
that pythonically build requests and parse responses,
|
|
5
|
+
following the [RFC7643](https://datatracker.ietf.org/doc/html/rfc7643.html) and [RFC7644](https://datatracker.ietf.org/doc/html/rfc7644.html) specifications.
|
|
4
6
|
## Installation
|
|
5
7
|
|
|
6
8
|
```shell
|
|
@@ -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.1"
|
|
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.1"
|
|
31
31
|
|
|
32
32
|
[tool.poetry.group.doc]
|
|
33
33
|
optional = true
|
|
@@ -10,6 +10,7 @@ from httpx import Client
|
|
|
10
10
|
from httpx import Response
|
|
11
11
|
from pydantic import ValidationError
|
|
12
12
|
from scim2_models import AnyResource
|
|
13
|
+
from scim2_models import Context
|
|
13
14
|
from scim2_models import Error
|
|
14
15
|
from scim2_models import ListResponse
|
|
15
16
|
from scim2_models import PatchOp
|
|
@@ -44,6 +45,7 @@ class SCIMClient:
|
|
|
44
45
|
response: Response,
|
|
45
46
|
expected_status_codes: List[int],
|
|
46
47
|
expected_type: Optional[Type] = None,
|
|
48
|
+
scim_ctx: Optional[Context] = None,
|
|
47
49
|
):
|
|
48
50
|
if response.status_code not in expected_status_codes:
|
|
49
51
|
raise UnexpectedStatusCode(response)
|
|
@@ -77,7 +79,8 @@ class SCIMClient:
|
|
|
77
79
|
pass
|
|
78
80
|
|
|
79
81
|
if expected_type:
|
|
80
|
-
return expected_type.model_validate(response_payload)
|
|
82
|
+
return expected_type.model_validate(response_payload, scim_ctx=scim_ctx)
|
|
83
|
+
|
|
81
84
|
return response_payload
|
|
82
85
|
|
|
83
86
|
def create(self, resource: AnyResource, **kwargs) -> Union[AnyResource, Error]:
|
|
@@ -95,7 +98,7 @@ class SCIMClient:
|
|
|
95
98
|
|
|
96
99
|
self.check_resource_type(resource.__class__)
|
|
97
100
|
url = self.resource_endpoint(resource.__class__)
|
|
98
|
-
dump = resource.model_dump(
|
|
101
|
+
dump = resource.model_dump(scim_ctx=Context.RESOURCE_CREATION_REQUEST)
|
|
99
102
|
response = self.client.post(url, json=dump, **kwargs)
|
|
100
103
|
|
|
101
104
|
expected_status_codes = [
|
|
@@ -113,7 +116,12 @@ class SCIMClient:
|
|
|
113
116
|
404,
|
|
114
117
|
500,
|
|
115
118
|
]
|
|
116
|
-
return self.check_response(
|
|
119
|
+
return self.check_response(
|
|
120
|
+
response,
|
|
121
|
+
expected_status_codes,
|
|
122
|
+
resource.__class__,
|
|
123
|
+
scim_ctx=Context.RESOURCE_CREATION_RESPONSE,
|
|
124
|
+
)
|
|
117
125
|
|
|
118
126
|
def query(
|
|
119
127
|
self,
|
|
@@ -142,7 +150,8 @@ class SCIMClient:
|
|
|
142
150
|
self.check_resource_type(resource_type)
|
|
143
151
|
payload = (
|
|
144
152
|
search_request.model_dump(
|
|
145
|
-
|
|
153
|
+
exclude_unset=True,
|
|
154
|
+
scim_ctx=Context.RESOURCE_QUERY_REQUEST,
|
|
146
155
|
)
|
|
147
156
|
if search_request
|
|
148
157
|
else None
|
|
@@ -171,7 +180,12 @@ class SCIMClient:
|
|
|
171
180
|
500,
|
|
172
181
|
]
|
|
173
182
|
response = self.client.get(url, params=payload, **kwargs)
|
|
174
|
-
return self.check_response(
|
|
183
|
+
return self.check_response(
|
|
184
|
+
response,
|
|
185
|
+
expected_status_codes,
|
|
186
|
+
expected_type,
|
|
187
|
+
scim_ctx=Context.RESOURCE_QUERY_RESPONSE,
|
|
188
|
+
)
|
|
175
189
|
|
|
176
190
|
def query_all(
|
|
177
191
|
self,
|
|
@@ -196,7 +210,7 @@ class SCIMClient:
|
|
|
196
210
|
|
|
197
211
|
payload = (
|
|
198
212
|
search_request.model_dump(
|
|
199
|
-
|
|
213
|
+
exclude_unset=True, scim_ctx=Context.RESOURCE_QUERY_REQUEST
|
|
200
214
|
)
|
|
201
215
|
if search_request
|
|
202
216
|
else None
|
|
@@ -220,7 +234,10 @@ class SCIMClient:
|
|
|
220
234
|
]
|
|
221
235
|
|
|
222
236
|
return self.check_response(
|
|
223
|
-
response,
|
|
237
|
+
response,
|
|
238
|
+
expected_status_codes,
|
|
239
|
+
ListResponse[Union[self.resource_types]],
|
|
240
|
+
scim_ctx=Context.RESOURCE_QUERY_RESPONSE,
|
|
224
241
|
)
|
|
225
242
|
|
|
226
243
|
def search(
|
|
@@ -244,7 +261,7 @@ class SCIMClient:
|
|
|
244
261
|
|
|
245
262
|
payload = (
|
|
246
263
|
search_request.model_dump(
|
|
247
|
-
|
|
264
|
+
exclude_unset=True, scim_ctx=Context.RESOURCE_QUERY_RESPONSE
|
|
248
265
|
)
|
|
249
266
|
if search_request
|
|
250
267
|
else None
|
|
@@ -269,7 +286,10 @@ class SCIMClient:
|
|
|
269
286
|
501,
|
|
270
287
|
]
|
|
271
288
|
return self.check_response(
|
|
272
|
-
response,
|
|
289
|
+
response,
|
|
290
|
+
expected_status_codes,
|
|
291
|
+
ListResponse[Union[self.resource_types]],
|
|
292
|
+
scim_ctx=Context.RESOURCE_QUERY_RESPONSE,
|
|
273
293
|
)
|
|
274
294
|
|
|
275
295
|
def delete(self, resource_type: Type, id: str, **kwargs) -> Optional[Error]:
|
|
@@ -323,7 +343,7 @@ class SCIMClient:
|
|
|
323
343
|
if not resource.id:
|
|
324
344
|
raise Exception("Resource must have an id")
|
|
325
345
|
|
|
326
|
-
dump = resource.model_dump(
|
|
346
|
+
dump = resource.model_dump(scim_ctx=Context.RESOURCE_REPLACEMENT_REQUEST)
|
|
327
347
|
url = self.resource_endpoint(resource.__class__) + f"/{resource.id}"
|
|
328
348
|
response = self.client.put(url, json=dump, **kwargs)
|
|
329
349
|
|
|
@@ -344,7 +364,12 @@ class SCIMClient:
|
|
|
344
364
|
500,
|
|
345
365
|
501,
|
|
346
366
|
]
|
|
347
|
-
return self.check_response(
|
|
367
|
+
return self.check_response(
|
|
368
|
+
response,
|
|
369
|
+
expected_status_codes,
|
|
370
|
+
resource.__class__,
|
|
371
|
+
scim_ctx=Context.RESOURCE_REPLACEMENT_RESPONSE,
|
|
372
|
+
)
|
|
348
373
|
|
|
349
374
|
def modify(
|
|
350
375
|
self, resource: AnyResource, op: PatchOp, **kwargs
|
|
File without changes
|
|
File without changes
|