scim2-client 0.1.6__tar.gz → 0.1.8__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.6 → scim2_client-0.1.8}/PKG-INFO +5 -5
- {scim2_client-0.1.6 → scim2_client-0.1.8}/README.md +2 -2
- {scim2_client-0.1.6 → scim2_client-0.1.8}/pyproject.toml +5 -5
- {scim2_client-0.1.6 → scim2_client-0.1.8}/scim2_client/client.py +38 -26
- {scim2_client-0.1.6 → scim2_client-0.1.8}/scim2_client/__init__.py +0 -0
- {scim2_client-0.1.6 → scim2_client-0.1.8}/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.8
|
|
4
4
|
Summary: Pythonically build SCIM requests and parse SCIM responses
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: scim,scim2,provisioning,httpx,api
|
|
@@ -19,8 +19,8 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
21
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
22
|
-
Requires-Dist: httpx (>=0.
|
|
23
|
-
Requires-Dist: scim2-models (>=0.1.
|
|
22
|
+
Requires-Dist: httpx (>=0.24.0,<0.25.0)
|
|
23
|
+
Requires-Dist: scim2-models (>=0.1.9,<0.2.0)
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
25
25
|
|
|
26
26
|
# scim2-client
|
|
@@ -67,9 +67,9 @@ assert user.meta.last_updated == datetime.datetime(
|
|
|
67
67
|
)
|
|
68
68
|
|
|
69
69
|
# Update resources
|
|
70
|
-
user.display_name = "
|
|
70
|
+
user.display_name = "Babs Jensen"
|
|
71
71
|
user = scim.replace(user)
|
|
72
|
-
assert user.display_name == "
|
|
72
|
+
assert user.display_name == "Babs Jensen"
|
|
73
73
|
assert user.meta.last_updated == datetime.datetime(
|
|
74
74
|
2024, 4, 13, 12, 0, 30, tzinfo=datetime.timezone.utc
|
|
75
75
|
)
|
|
@@ -42,9 +42,9 @@ assert user.meta.last_updated == datetime.datetime(
|
|
|
42
42
|
)
|
|
43
43
|
|
|
44
44
|
# Update resources
|
|
45
|
-
user.display_name = "
|
|
45
|
+
user.display_name = "Babs Jensen"
|
|
46
46
|
user = scim.replace(user)
|
|
47
|
-
assert user.display_name == "
|
|
47
|
+
assert user.display_name == "Babs Jensen"
|
|
48
48
|
assert user.meta.last_updated == datetime.datetime(
|
|
49
49
|
2024, 4, 13, 12, 0, 30, tzinfo=datetime.timezone.utc
|
|
50
50
|
)
|
|
@@ -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.8"
|
|
8
8
|
description = "Pythonically build SCIM requests and parse SCIM responses"
|
|
9
9
|
authors = ["Yaal Coop <contact@yaal.coop>"]
|
|
10
10
|
license = "MIT"
|
|
@@ -26,8 +26,8 @@ classifiers = [
|
|
|
26
26
|
|
|
27
27
|
[tool.poetry.dependencies]
|
|
28
28
|
python = "^3.9"
|
|
29
|
-
httpx = "^0.
|
|
30
|
-
scim2-models = "^0.1.
|
|
29
|
+
httpx = "^0.24.0"
|
|
30
|
+
scim2-models = "^0.1.9"
|
|
31
31
|
|
|
32
32
|
[tool.poetry.group.doc]
|
|
33
33
|
optional = true
|
|
@@ -38,10 +38,10 @@ pytest-coverage = "^0.0"
|
|
|
38
38
|
pytest-httpserver = "^1.0.10"
|
|
39
39
|
|
|
40
40
|
[tool.poetry.group.doc.dependencies]
|
|
41
|
+
autodoc-pydantic = "^2.2.0"
|
|
42
|
+
myst-parser = "^3.0.1"
|
|
41
43
|
shibuya = "^2024.5.15"
|
|
42
44
|
sphinx = "^7.3.7"
|
|
43
|
-
myst-parser = "^3.0.1"
|
|
44
|
-
autodoc-pydantic = "^2.2.0"
|
|
45
45
|
|
|
46
46
|
[tool.coverage.run]
|
|
47
47
|
source = [
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import json.decoder
|
|
3
|
+
import sys
|
|
3
4
|
from typing import Dict
|
|
4
5
|
from typing import List
|
|
5
6
|
from typing import Optional
|
|
@@ -62,12 +63,18 @@ class SCIMClient:
|
|
|
62
63
|
404,
|
|
63
64
|
500,
|
|
64
65
|
]
|
|
65
|
-
"""Resource creation HTTP codes
|
|
66
|
-
|
|
66
|
+
"""Resource creation HTTP codes.
|
|
67
|
+
|
|
68
|
+
As defined at :rfc:`RFC7644 §3.3 <7644#section-3.3>` and
|
|
69
|
+
:rfc:`RFC7644 §3.12 <7644#section-3.12>`.
|
|
70
|
+
"""
|
|
67
71
|
|
|
68
72
|
QUERY_RESPONSE_STATUS_CODES: List[int] = [200, 400, 307, 308, 401, 403, 404, 500]
|
|
69
|
-
"""Resource querying HTTP codes
|
|
70
|
-
|
|
73
|
+
"""Resource querying HTTP codes.
|
|
74
|
+
|
|
75
|
+
As defined at :rfc:`RFC7644 §3.4.2 <7644#section-3.4.2>` and
|
|
76
|
+
:rfc:`RFC7644 §3.12 <7644#section-3.12>`.
|
|
77
|
+
"""
|
|
71
78
|
|
|
72
79
|
SEARCH_RESPONSE_STATUS_CODES: List[int] = [
|
|
73
80
|
200,
|
|
@@ -82,8 +89,11 @@ class SCIMClient:
|
|
|
82
89
|
500,
|
|
83
90
|
501,
|
|
84
91
|
]
|
|
85
|
-
"""Resource querying HTTP codes
|
|
86
|
-
|
|
92
|
+
"""Resource querying HTTP codes.
|
|
93
|
+
|
|
94
|
+
As defined at :rfc:`RFC7644 §3.4.3 <7644#section-3.4.3>` and
|
|
95
|
+
:rfc:`RFC7644 §3.12 <7644#section-3.12>`.
|
|
96
|
+
"""
|
|
87
97
|
|
|
88
98
|
DELETION_RESPONSE_STATUS_CODES: List[int] = [
|
|
89
99
|
204,
|
|
@@ -97,8 +107,11 @@ class SCIMClient:
|
|
|
97
107
|
500,
|
|
98
108
|
501,
|
|
99
109
|
]
|
|
100
|
-
"""Resource deletion HTTP codes
|
|
101
|
-
|
|
110
|
+
"""Resource deletion HTTP codes.
|
|
111
|
+
|
|
112
|
+
As defined at :rfc:`RFC7644 §3.6 <7644#section-3.6>` and
|
|
113
|
+
:rfc:`RFC7644 §3.12 <7644#section-3.12>`.
|
|
114
|
+
"""
|
|
102
115
|
|
|
103
116
|
REPLACEMENT_RESPONSE_STATUS_CODES: List[int] = [
|
|
104
117
|
200,
|
|
@@ -113,8 +126,11 @@ class SCIMClient:
|
|
|
113
126
|
500,
|
|
114
127
|
501,
|
|
115
128
|
]
|
|
116
|
-
"""Resource querying HTTP codes
|
|
117
|
-
|
|
129
|
+
"""Resource querying HTTP codes.
|
|
130
|
+
|
|
131
|
+
As defined at :rfc:`RFC7644 §3.4.2 <7644#section-3.4.2>` and
|
|
132
|
+
:rfc:`RFC7644 §3.12 <7644#section-3.12>`.
|
|
133
|
+
"""
|
|
118
134
|
|
|
119
135
|
def __init__(self, client: Client, resource_types: Optional[Tuple[Type]] = None):
|
|
120
136
|
self.client = client
|
|
@@ -180,13 +196,14 @@ class SCIMClient:
|
|
|
180
196
|
if not check_response_payload:
|
|
181
197
|
return response_payload
|
|
182
198
|
|
|
183
|
-
|
|
199
|
+
if (
|
|
200
|
+
response_payload
|
|
201
|
+
and response_payload.get("schemas") == Error.model_fields["schemas"].default
|
|
202
|
+
):
|
|
184
203
|
error = Error.model_validate(response_payload)
|
|
185
204
|
if raise_scim_errors:
|
|
186
205
|
raise SCIMResponseErrorObject(source=error)
|
|
187
206
|
return error
|
|
188
|
-
except ValidationError:
|
|
189
|
-
pass
|
|
190
207
|
|
|
191
208
|
if not expected_types:
|
|
192
209
|
return response_payload
|
|
@@ -211,7 +228,7 @@ class SCIMClient:
|
|
|
211
228
|
return actual_type.model_validate(response_payload, scim_ctx=scim_ctx)
|
|
212
229
|
except ValidationError as exc:
|
|
213
230
|
scim_exc = ResponsePayloadValidationError(source=response)
|
|
214
|
-
if
|
|
231
|
+
if sys.version_info >= (3, 11): # pragma: no cover
|
|
215
232
|
scim_exc.add_note(str(exc))
|
|
216
233
|
raise scim_exc from exc
|
|
217
234
|
|
|
@@ -261,7 +278,6 @@ class SCIMClient:
|
|
|
261
278
|
which value will excluded from the request payload, and which values are expected in
|
|
262
279
|
the response payload.
|
|
263
280
|
"""
|
|
264
|
-
|
|
265
281
|
if not check_request_payload:
|
|
266
282
|
payload = resource
|
|
267
283
|
url = kwargs.pop("url", None)
|
|
@@ -281,7 +297,7 @@ class SCIMClient:
|
|
|
281
297
|
resource = resource_type.model_validate(resource)
|
|
282
298
|
except ValidationError as exc:
|
|
283
299
|
scim_exc = RequestPayloadValidationError(source=resource)
|
|
284
|
-
if
|
|
300
|
+
if sys.version_info >= (3, 11): # pragma: no cover
|
|
285
301
|
scim_exc.add_note(str(exc))
|
|
286
302
|
raise scim_exc from exc
|
|
287
303
|
|
|
@@ -293,7 +309,7 @@ class SCIMClient:
|
|
|
293
309
|
response = self.client.post(url, json=payload, **kwargs)
|
|
294
310
|
except RequestError as exc:
|
|
295
311
|
scim_exc = RequestNetworkError(source=payload)
|
|
296
|
-
if
|
|
312
|
+
if sys.version_info >= (3, 11): # pragma: no cover
|
|
297
313
|
scim_exc.add_note(str(exc))
|
|
298
314
|
raise scim_exc from exc
|
|
299
315
|
|
|
@@ -382,7 +398,6 @@ class SCIMClient:
|
|
|
382
398
|
which value will excluded from the request payload, and which values are expected in
|
|
383
399
|
the response payload.
|
|
384
400
|
"""
|
|
385
|
-
|
|
386
401
|
if resource_type and check_request_payload:
|
|
387
402
|
self.check_resource_type(resource_type)
|
|
388
403
|
|
|
@@ -423,7 +438,7 @@ class SCIMClient:
|
|
|
423
438
|
response = self.client.get(url, params=payload, **kwargs)
|
|
424
439
|
except RequestError as exc:
|
|
425
440
|
scim_exc = RequestNetworkError(source=payload)
|
|
426
|
-
if
|
|
441
|
+
if sys.version_info >= (3, 11): # pragma: no cover
|
|
427
442
|
scim_exc.add_note(str(exc))
|
|
428
443
|
raise scim_exc from exc
|
|
429
444
|
|
|
@@ -486,7 +501,6 @@ class SCIMClient:
|
|
|
486
501
|
which value will excluded from the request payload, and which values are expected in
|
|
487
502
|
the response payload.
|
|
488
503
|
"""
|
|
489
|
-
|
|
490
504
|
if not check_request_payload:
|
|
491
505
|
payload = search_request
|
|
492
506
|
|
|
@@ -505,7 +519,7 @@ class SCIMClient:
|
|
|
505
519
|
response = self.client.post(url, json=payload)
|
|
506
520
|
except RequestError as exc:
|
|
507
521
|
scim_exc = RequestNetworkError(source=payload)
|
|
508
|
-
if
|
|
522
|
+
if sys.version_info >= (3, 11): # pragma: no cover
|
|
509
523
|
scim_exc.add_note(str(exc))
|
|
510
524
|
raise scim_exc from exc
|
|
511
525
|
|
|
@@ -557,7 +571,6 @@ class SCIMClient:
|
|
|
557
571
|
response = scim.delete(User, "foobar")
|
|
558
572
|
# 'response' may be None, or an Error object
|
|
559
573
|
"""
|
|
560
|
-
|
|
561
574
|
self.check_resource_type(resource_type)
|
|
562
575
|
delete_url = self.resource_endpoint(resource_type) + f"/{id}"
|
|
563
576
|
url = kwargs.pop("url", delete_url)
|
|
@@ -566,7 +579,7 @@ class SCIMClient:
|
|
|
566
579
|
response = self.client.delete(url, **kwargs)
|
|
567
580
|
except RequestError as exc:
|
|
568
581
|
scim_exc = RequestNetworkError()
|
|
569
|
-
if
|
|
582
|
+
if sys.version_info >= (3, 11): # pragma: no cover
|
|
570
583
|
scim_exc.add_note(str(exc))
|
|
571
584
|
raise scim_exc from exc
|
|
572
585
|
|
|
@@ -627,7 +640,6 @@ class SCIMClient:
|
|
|
627
640
|
which value will excluded from the request payload, and which values are expected in
|
|
628
641
|
the response payload.
|
|
629
642
|
"""
|
|
630
|
-
|
|
631
643
|
if not check_request_payload:
|
|
632
644
|
payload = resource
|
|
633
645
|
url = kwargs.pop("url", None)
|
|
@@ -648,7 +660,7 @@ class SCIMClient:
|
|
|
648
660
|
resource = resource_type.model_validate(resource)
|
|
649
661
|
except ValidationError as exc:
|
|
650
662
|
scim_exc = RequestPayloadValidationError(source=resource)
|
|
651
|
-
if
|
|
663
|
+
if sys.version_info >= (3, 11): # pragma: no cover
|
|
652
664
|
scim_exc.add_note(str(exc))
|
|
653
665
|
raise scim_exc from exc
|
|
654
666
|
|
|
@@ -666,7 +678,7 @@ class SCIMClient:
|
|
|
666
678
|
response = self.client.put(url, json=payload, **kwargs)
|
|
667
679
|
except RequestError as exc:
|
|
668
680
|
scim_exc = RequestNetworkError(source=payload)
|
|
669
|
-
if
|
|
681
|
+
if sys.version_info >= (3, 11): # pragma: no cover
|
|
670
682
|
scim_exc.add_note(str(exc))
|
|
671
683
|
raise scim_exc from exc
|
|
672
684
|
|
|
File without changes
|
|
File without changes
|